Angenommen, es gibt Text aus einer Datei:
(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)
Ich möchte zu jeder Zahl 11 addieren, gefolgt von einem "
in jeder Zeile, wenn es eine gibt, dh
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)
Hier ist meine Lösung mit GNU AWK und Regex:
awk -F'#' 'NF>1{gsub(/"(\d+)\""/, "\1+11\"")}'
dh ich möchte ersetzen (\d+)\"
durch \1+10\"
, wo \1
die Gruppe darstellt (\d+)
. Aber es geht nicht. Wie kann ich es zum Laufen bringen?
Wenn Gawk nicht die beste Lösung ist, was kann sonst noch verwendet werden?
regular-expression
awk
text-processing
StackExchange für alle
quelle
quelle
Antworten:
Versuchen Sie dies (Gawk wird benötigt).
Testen Sie mit Ihrem Beispiel:
Beachten Sie, dass dieser Befehl nicht funktioniert, wenn sich die beiden Zahlen (z. B. 1 "und" # 1 ") unterscheiden oder wenn sich mehrere Zahlen in derselben Zeile mit diesem Muster befinden (z. B. 23" ... 32 "..." # 123 ") in einer Zeile.
AKTUALISIEREN
Da @Tim (OP) angibt, dass die Zahl, die
"
in derselben Zeile steht, unterschiedlich sein kann, habe ich einige Änderungen an meiner vorherigen Lösung vorgenommen und sie für Ihr neues Beispiel funktionsfähig gemacht.Übrigens, aufgrund des Beispiels habe ich das Gefühl, dass es sich um ein Inhaltsverzeichnis handeln könnte, sodass ich nicht sehe, wie sich die beiden Zahlen unterscheiden könnten. Das erste wäre die gedruckte Seitennummer und das zweite mit # wäre der Seitenindex. Habe ich recht?
Wie auch immer, Sie kennen Ihre Anforderungen am besten. Jetzt die neue Lösung, immer noch mit Gawk (ich teile den Befehl in Zeilen auf, um das Lesen zu erleichtern):
teste mit deinem neuen Beispiel:
EDIT2 basierend auf @Tims Kommentar
Sie sind sowohl im Eingabe- als auch im Ausgabeteil für das Trennzeichen richtig. Es definierte Trennzeichen als:
Es gibt zwei doppelte Anführungszeichen, da es einfacher ist, die beiden gewünschten Zahlen zu erfassen (basierend auf Ihrer Beispieleingabe).
Genau!
Dies ist von http://www.gnu.org/s/gawk/manual/html_node/String-Functions.html . Sie können lesen, um eine detaillierte Verwendung von gensub zu erhalten.
quelle
awk -F'#'
scheint, dass Sie die Änderung nur für den Teil nach dem '#' vornehmen möchten?FS=OFS="\" \"#"
dass das Feldtrennzeichen in Eingabe und Ausgabe doppelte Anführungszeichen, Leerzeichen, doppelte Anführungszeichen und # ist? warum doppeltes Anführungszeichen zweimal angeben? (2) in/.* ([0-9]+)$/
,$
bedeutet das Ende der Zeichenkette? (3) Was ist der Unterschied zwischen"g"
und im dritten Argument von gensub ()"G"
?Im Gegensatz zu fast jedem Tool, das reguläre Ausdrücke ersetzt, lässt awk keine Rückverweise wie
\1
im Ersatztext zu. GNU Awk ermöglicht den Zugriff auf übereinstimmende Gruppen, wenn Sie diematch
Funktion verwenden , jedoch nicht mit~
odersub
odergsub
.Beachten Sie auch, dass
\1
Ihr Snippet , selbst wenn es unterstützt wird, die Zeichenfolge anhängt+11
und keine numerische Berechnung durchführt. Außerdem stimmt Ihr regulärer Ausdruck nicht ganz, Sie passen zu Dingen wie"42""
und nicht"#42"
.Hier ist eine awk-Lösung (Warnung, ungetestet). Es wird nur ein einziger Austausch pro Zeile durchgeführt.
In Perl wäre es einfacher.
quelle
awk
kann es, aber es ist nicht direkt, auch mit Rückverweisen.GNU awk hat eine (teilweise) Rückreferenzierung in Form von gensub .
Instanzen von
123"
werden vorübergehend eingepackt\x01
und\x02
als unmodifiziert markiert (zsub()
. B. coOder Sie können einfach durch die Schleife gehen und dabei die Kandidaten wechseln. In diesem Fall sind die Rückverweise und "Klammern" nicht erforderlich. Es ist jedoch erforderlich, den Zeichenindex im Auge zu behalten.
Hier ist eine andere Art und Weise, unter Verwendung
gensub
und Anordnungsplit
und\x01
als ein Feldtrennzeichen (für Split ) .. \ x02 Markierungen ein Array - Element als ein Kandidat für die arithmetische Addition.quelle
"\x01\\1\"\x02"
? Ich verstehe immer noch nicht\x01
und\x02
. (2) Wie unterschiedlich ist die Rückkehr$0
vongensub
und die$0
als letztes Argumentgensub
?\x01
und\x02
werden als Substitutionsmarker verwendet. Es ist sehr unwahrscheinlich, dass diese Werte in einer normalen Textdatei enthalten sind, daher sind sie auch "sehr" sicher zu verwenden (dh sie stoßen nicht auf einen Konflikt mit bereits vorhandenen). Es handelt sich lediglich um temporäre Bezeichnungen$0=gensub(... $0)
. Siehe hierzu verknüpfe String-Manipulationsfunktionen , aber zusammenfassend: Es (gensub) gibt den modifizierten String als Ergebnis der Funktion zurück und der ursprüngliche Ziel-String wird nicht geändert. ... Das$0=
ändert einfach das ursprüngliche Ziel ..Da die Lösungen in (g) awk recht komplex zu sein scheinen, wollte ich in Perl eine alternative Lösung hinzufügen:
Erläuterung:
-w
aktiviert Warnungen (die Sie vor möglichen unerwünschten Auswirkungen warnen).-p
impliziert eine Schleife um den Code, die sed oder awk ähnelt und jede Eingabezeile automatisch in der Standardvariablen speichert$_
.-e
teilt Perl mit, dass der Programmcode in der Befehlszeile und nicht in einer Skriptdatei folgt.s/.../.../
) an$_
, bei der eine Ziffernfolge, wenn sie von einem gefolgt"
wird, durch die Folge ersetzt wird, die als Zahl in der Addition plus 11 interpretiert wird.(?=pattern)
der Breite Null sucht die,"
ohne sie in das Match aufzunehmen, sodass wir sie bei der Ersetzung nicht wiederholen müssen. Die MATCH-Variable$&
in der Ersetzung enthält dann nur die Nummer./e
Regex-Modifikator weistperl
an, die Ersetzung als Code "auszuführen", anstatt sie als Zeichenfolge zu verwenden./g
Modifikator macht die Ersetzung "global" und wiederholt sie bei jeder Übereinstimmung in der Zeile.Die MATCH-Variable
$&
wird die Code-Performance in Perl-Versionen vor 5.20 leider beeinträchtigen. Eine schnellere (und nicht viel komplexere) Lösung würde$1
stattdessen die Gruppierung und den Rückverweis verwenden:Und wenn die Vorausschau-Behauptung zu verwirrend aussieht, können Sie das Anführungszeichen auch explizit ersetzen:
quelle