So ersetzen Sie alle Zeichenfolgen in einer Datei, die mit einem Präfix beginnen

7

Beispiel:

1:20 2:25 3:0.432 2:-17 10:12

Ich möchte alle Zeichenfolgen ersetzen, die mit 2:to beginnen2:0 .

Ausgabe:

1:20 2:0 3:0.432 2:0 10:12
Roy
quelle
1
Was ist mit 2:genau passenden Strings ? Sollten diese ersetzt werden?
Kos

Antworten:

15

Verwenden von sed:

sed -E 's/((^| )2:)[^ ]*/\10/g' in > out

Auch, wie inspiriert souravc Antwort , wenn es nicht eine Chance auf einen 2:Teilstring nach dem Beginn eines Strings nicht ein führendes enthält 2:String (zB gibt es nicht eine Chance auf eine 1:202:25Zeichenfolge, die der folgende Kurzbefehl ersetzen würde 1:202:0), das Befehl kann auf diesen verkürzt werden:

sed -E 's/2:[^ ]*/2:0/g' in > out

Befehl # 1 / # 2 Aufschlüsselung :

  • -E: lässt seddas Muster als ERE-Muster (Extended Regular Expression) interpretieren;
  • > out: leitet weiter stdoutzu out;

sedBefehl # 1 Aufschlüsselung :

  • s: behauptet, eine Substitution durchzuführen
  • /: Startet das Muster
  • (: Startet die Erfassungsgruppe
  • (: Startet die Gruppierung der zulässigen Zeichenfolgen
  • ^: Entspricht dem Zeilenanfang
  • |: trennt die zweite zulässige Zeichenfolge
  • : Entspricht einem Zeichen
  • ): Beendet die Gruppierung der zulässigen Zeichenfolgen
  • 2: Entspricht einem 2Zeichen
  • :: Entspricht einem :Zeichen
  • ): Stoppt die Erfassungsgruppe
  • [^ ]*: Entspricht einer beliebigen Anzahl von Zeichen nicht
  • /: stoppt das Muster / startet die Ersatzzeichenfolge
  • \1: Rückreferenz durch die erste Erfassungsgruppe ersetzt
  • 0: fügt ein 0Zeichen hinzu
  • /: stoppt die Ersatzzeichenfolge / startet die Musterflags
  • g: behauptet, die Ersetzung global durchzuführen, dh jedes Vorkommen des Musters in der Zeile zu ersetzen

sedBefehl # 2 Aufschlüsselung :

  • s: behauptet, eine Substitution durchzuführen
  • /: Startet das Muster
  • 2: Entspricht einem 2Zeichen
  • :: Entspricht einem :Zeichen
  • [^ ]*: Entspricht einer beliebigen Anzahl von Zeichen nicht
  • /: stoppt das Muster / startet die Ersatzzeichenfolge
  • 2:0: fügt eine 2:0Zeichenfolge hinzu
  • /: stoppt die Ersatzzeichenfolge / startet die Musterflags
  • g: behauptet, die Ersetzung global durchzuführen, dh jedes Vorkommen des Musters in der Zeile zu ersetzen
kos
quelle
Schnell wie immer :) +1
AB
4

Dieser eine Liner mit sed

sed -i.bkp 's/2:\([0-9]*\)\|2:\(-\)\([0-9]*\)/2:0/g' input_file

wird ersetzen global in Zeile in input_fileeine Backup - Datei mit dem Namen hält input_file.bkpim gleichen Verzeichnis.

Dies kann weiter verkürzen erweiterte reguläre Ausdrücke verwenden , wie vorgeschlagen von kos, wie

sed -ri.bkp 's/2:\-?[0-9]*/2:0/g' input_file
Souravc
quelle
Wenn Sie beide Zeichenfolgen abgleichen möchten 2:und 2:-nur die -optionale Übereinstimmung mit erweiterten regulären Ausdrücken vornehmen möchten ( -rOption); Außerdem müssen Sie nichts erfassen, da Sie nichts ersetzen:sed -ri.bkp 's/2:\-?[0-9]*/2:0/g' input_file
Kos
2

Ich würde eine Basisschleife verwenden awk:

$ awk '{for (i=1; i<=NF; i++) $i~/^2:/ && $i="2:0"}1' file
1:20 2:0 3:0.432 2:0 10:12

Dies durchläuft alle Felder. Immer wenn einer von ihnen mit beginnt 2:, ersetzt er alles durch 2:0. Schließlich 1steht das für True, so dass die gesamte Zeile gedruckt wird.

fedorqui
quelle
1

Verwenden von python:

#!/usr/bin/env python2
import re
with open('test_dir/unix_se.txt') as f:
    for line in f:
        print re.sub(r'(?:(?<=(?: 2:))|(?<=(?:^2:)))[^ ]*', '0', line).rstrip()

Hier haben wir die re.subFunktion des reModuls verwendet.

  • re.sub() hat das Muster sub(pattern, repl, string, count=0, flags=0)

  • Da wir die Werte innerhalb der Gruppe nicht weiter verwenden werden, haben wir die nicht erfassende Gruppennotation verwendet (?:)

  • (?:(?<=(?: 2:))|(?<=(?:^2:)))Verwendet den positiven Blick nach hinten mit der Breite Null, um 2:zu Beginn oder gefolgt von einem Leerzeichen übereinzustimmen.

  • [^ ]*Entspricht null oder mehr Zeichen vor dem Leerzeichen, danach 2:und ersetzt sie durch 0.

Hier ist ein Beispiel:

Eingang:

2:456 1:20 2:25 3:0.432 2:-17 10:12
1:20 2:25 3:0.432 2:-17 10:12 2:543 2:-78

Ausgabe:

2:0 1:20 2:0 3:0.432 2:0 10:12
1:20 2:0 3:0.432 2:0 10:12 2:0 2:0
heemayl
quelle
0

Danke @kos für die sedVersion:

Einige kleine Modifikationen für den perlWeg:

perl -pe 's/((^|\s)2:)[^\s]*/${1}0/g' testdata

Schreiben Sie zurück mit:

perl -i -pe 's/((^|\s)2:)[^\s]*/${1}0/g' testdata

Erläuterung:

((^|\s)2:)[^\s]*

Visualisierung regulärer Ausdrücke

Debuggex-Demo

  • 1. Erfassungsgruppe ((^|\s)2:)

    • 2. Erfassungsgruppe (^|\s)
    • 1. Alternative: ^

      ^ Position am Anfang der Zeichenfolge bestätigen

    • 2. Alternative: \s

      \s Entspricht einem beliebigen Leerzeichen [\r\n\t\f ]

    2:stimmt 2:buchstäblich mit den Zeichen überein

  • [^\s]* stimmen mit einem einzelnen Zeichen überein, das in der folgenden Liste nicht vorhanden ist

    Quantifizierer: *Zwischen null und unbegrenzt, so oft wie möglich, nach Bedarf zurückgeben [gierig]

    \s Entspricht einem beliebigen Leerzeichen [\r\n\t\f ]


Oder mit einem positiven Lookbehind , thx @steeldriver

perl -pe 's/(?<=2:)\S*/0/g' testdata

Erläuterung

(?<=2:)\S*

Visualisierung regulärer Ausdrücke

  • (?<=2:) Positives Aussehen - Stellen Sie sicher, dass der unten stehende reguläre Ausdruck übereinstimmen kann

    2:passt zu den Zeichen 2: buchstäblich

  • \S* Entspricht einem beliebigen Leerzeichen [^\r\n\t\f ]

    Quantifizierer: *Zwischen null und unbegrenzt, so oft wie möglich, nach Bedarf zurückgeben [gierig]

Debuggex-Demo

AB
quelle
2
Könnten Sie nicht einfach verwenden s/(?<=2:)\S*/0/g(alle folgenden Folgen von Nicht-Leerzeichen ersetzen 2:durch 0)?
Steeldriver
@steeldriver Nein, egal, ich habe deine Aussage falsch interpretiert, dein Vorschlag ist gut
kos
@steeldriver Ja, Lookbehind und Lookahead sind großartig.
AB
1
@kos eigentlich hätte ich vielleicht eher vorschlagen sollen, S+als S*eine leere Zeichenfolge zu ersetzen, 2:dh 2:wird 2:0, was möglicherweise nicht das beabsichtigte Verhalten ist
steeldriver
@steeldriver Ich stimme zu. OP sollte dies klarstellen
kos