ubuntuusers.de

Benötige Hilfe im Umgang mit sed/reg. expressions

Status: Ungelöst | Ubuntu-Version: Ubuntu 13.10 (Saucy Salamander)
Antworten |

pc_heini

Anmeldungsdatum:
29. April 2009

Beiträge: 27

Hallo,

lange Zeit konnte ich mich von reg. expressions fern halten aber früher oder später muss ich damit klarkommen weswegen ich mir einige Tutorials anschaute und Versuche unternommen habe.

Privat besitze ich eine RAT7 Maus welche mit Linux, egal welcher Art, nicht klar kommt... deswegen testete und übte ich mit Notepad++...

Nun habe ich folgenden Anwendungsfall. Eine Zahlenreihe beginnend mit einer 8 und 2 weiteren Zahlen will modifiziert werden. Die 8 soll abgeändert werden, die weiteren decimals sollen beibehalten werden.

Beispiel: 80, 800, 812, 848, 890, 911

Hier sollen alle dreistelligen Zahlen beginnend mit 8 zu vierstelligen Zahlen beginnend mit 12 verändert werden.

Gewünschtes Ergebnis: 80, 1200, 1212, 1248, 1290, 911

Im Notepad++ habe ich dies so gemacht: Suche: 8(\d\d) Ersetze: 12$1

Quasi Suche alle Zahlen welche mit 8 beginnen und 2 Dezimalstellen haben, dabei setze die Dezimalstellen in die Variable $1. Beim Ersetzen schreibe eine 12 gefolgt von der Variablen.

Im Notepad++ funktioniert alles einwandfrei, im vim mittels sed jedoch erhalte ich no pattern found... und da fange ich an zu rätseln. ☹

Genauer Befehl in der Textdatei: : 1,$ s/8(\d\d)/12$1/g

Wo liegt hier mein Fehler? Könnt ihr mir bitte helfen? Danke im voraus!

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Ich glaube, Du solltest doch mal in das sed- Manual gucken ... 😉

Vergleich mal - einige Escapes sind bei sed nämlich ziemlich anders als Du sie schreibst: (nach Perl-Konvention, nehme ich an ?)

track@lucid:~$ echo '80, 800, 812, 848, 890, 911'  |  sed 's/8\([0-9][0-9]\)/12\1/g'
80, 1200, 1212, 1248, 1290, 911 

LG,

track

Keba Team-Icon

Ehemalige
Avatar von Keba

Anmeldungsdatum:
24. Juli 2007

Beiträge: 3802

Hallo,

track schrieb:

track@lucid:~$ echo '80, 800, 812, 848, 890, 911'  |  sed 's/8\([0-9][0-9]\)/12\1/g'
80, 1200, 1212, 1248, 1290, 911 

Das funktioniert zwar, aber in der Hoffnung etwas Verwirrung zu vermeiden: \d\d statt [0-9][0-9] geht natürlich auch (und ist m. W. sogar etwas schneller).

1,$

… soll was bewirken? Wenn du den Befehl auf die aktuelle Zeile ausführen möchtest, genügt :s…, die gesamte Datei erhälst du mittels :%s…. ☺

Grüße, Keba

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13174

Keba schrieb:

Das funktioniert zwar, aber in der Hoffnung etwas Verwirrung zu vermeiden: \d\d statt [0-9][0-9] geht natürlich auch (und ist m. W. sogar etwas schneller).

Bei welchem sed?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ echo 123 | sed 's#\d#X#g'
123
$ echo 123 | sed -r 's#\d#X#g'
123
$ sed --version
sed (GNU sed) 4.2.2
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jay Fenlason, Tom Lord, Ken Pizzini,
and Paolo Bonzini.
GNU-sed-Homepage: <http://www.gnu.org/software/sed/>.
Allgemeine Hilfe zu GNU-Software: <http://www.gnu.org/gethelp/>.
E-mail bug reports to: <bug-sed@gnu.org>.
Be sure to include the word ``sed'' somewhere in the ``Subject:'' field.

Meintest Du [[:digit:]]?

1
2
$ echo 123 | sed -r 's#[[:digit:]]#X#g'
XXX

Ich gebe auch noch zu bedenken, dass man Wordboundaries matchen sollte - sonst passiert das:

1
2
3
4
$ echo 7899 | sed 's/8\([0-9][0-9]\)/12\1/g'
71299
$ echo 8997 | sed 's/8\([0-9][0-9]\)/12\1/g'
12997

Das kann man vermeiden

1
2
3
4
5
6
$ echo 7899 | sed 's/\<8\([0-9][0-9]\)\>/12\1/g'
7899
$ echo 8997 | sed 's/\<8\([0-9][0-9]\)\>/12\1/g'
8997
$ echo 899 | sed 's/\<8\([0-9][0-9]\)\>/12\1/g'
1299

Ciao

robert

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Keba schrieb:

... \d\d statt [0-9][0-9] geht natürlich auch (und ist m. W. sogar etwas schneller).

Tut es das bei Dir ? - bei mir nämlich nicht. Und im Manual steht, dass \dxxx für die Dezimaldarstellung eines Bytes steht. 😉

1,$

… soll was bewirken?

Das bedeutet auch bei sed: "für Zeile 1 bis Ende" (wie Du schon sagst: ist überflüssig)

LG,

track

Keba Team-Icon

Ehemalige
Avatar von Keba

Anmeldungsdatum:
24. Juli 2007

Beiträge: 3802

😳

Ich hab nur im Vim getestet. Dort geht \d wie gewünscht. Wie der TE dachte ich, dass Vims substitute an sed angelehnt ist. Tja, hier gibt es scheinbar einen wichtigen Unterschied. Wieder was gelernt, danke ☺ Ich entschuldige mich bei pc heini für die unnötige Verwirrung.

track schrieb:

1,$

… soll was bewirken?

Das bedeutet auch bei sed: "für Zeile 1 bis Ende" (wie Du schon sagst: ist überflüssig)

In Vim scheint das etwas anders zu sein. Jedenfalls löscht 1,$;d nur die aktuelle Zeile, nicht den gesamten Buffer.

Grüße, Keba.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

Genau zwei Ziffern kann man auch mit {2} spezifizieren, und mit -r kann man den Backslash vor den runden Klammern weglassen:

1
echo '80, 800, 812, 848, 890, 911' | sed -r 's/8([[:digit:]]{2})/12\1/g'

Die Boundaries fehlen hier aber noch.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13174

Ergänzung: noch trennschärfer kann man das in Sprachen machen, die Lookround kennen:

1
2
3
4
5
6
$ echo 7899 | ruby -pe '$_.gsub! /(?<!\d)8(\d{2})(?!\d)/, "12\\1"'
7899
$ echo 8997 | ruby -pe '$_.gsub! /(?<!\d)8(\d{2})(?!\d)/, "12\\1"'
12997
$ echo 899 | ruby -pe '$_.gsub! /(?<!\d)8(\d{2})(?!\d)/, "12\\1"'
1299

Sonst passiert

1
2
3
4
$ echo a899 | sed 's/\<8\([0-9][0-9]\)\>/12\1/g'
a899
$ echo a899 | ruby -pe '$_.gsub! /(?<!\d)8(\d{2})(?!\d)/, "12\\1"'
a1299

Hängt halt davon ab, was man möchte. ☺

Ciao

robert

Antworten |