[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Sed Verständnisproblem



Hallo Gebhard,

Gebhard Dettmar <gebhard.dettmar@student.hu-berlin.de>
wrote:
> On Thursday 08 September 2005 21:49, Frank Dietrich wrote:
> > Mein Vorschlag wäre:
> > sed -e ':x;s/\(.*[A-Za-z]\) \+\([a-z]\)/\1\2/g;tx'
> >
> > :x - setzt ein Label
> >
> > s/\(.*[A-Za-z]\) \+\([a-z]\) - findet "[A-Z] [a-z]" und
> >      "[a-z] [a-z]", mit " " >=1 dazwischen,
> >      durch das ".*"es wird immer nach dem am weitesten rechts
> > liegende Pattern gesucht
> > \1\2 - dürfte klar sein
> > tx - wird das angegebene Pattern gefunden wird am Label x
> > fortgesetzt
> >
> > Ich hoffe die Erklärung ist leicht verständlich. ;-)
> 
> Nicht ganz. Das \+ (bzw. das Quoting vor dem +) verstehe ich nicht

Wurde von Mario schon erläutert.

> und die Erklärung zu Labels in der sed manpage ( Label for b and t
> commands???) auch nicht ;-(

Es wird sicher leichter verständlich wenn man die Anweisungen nicht
auf eine Zeile pappt sondern diese mittels einem Skript an sed
übergibt.

Angenommen Du sollst in einem Text "alle F O O B A R und FOOBAR in
Foobar wandeln.
Dann könnte man es in Pseudocode so lösen (dient nur als Beispiel,
und ist deshalb nur auf diesen einen Fall zugeschnitten):
- zuerst alle einzelnen Leerzeichen zwischen zwei Großbuchstaben
  löschen
- dann alle FOOBAR durch Foobar ersetzen

# alle einzelnen Leerzeichen zwischen zwei Großbuchstaben löschen
echo "F O O B A R  FOOBAR" | sed -e 's/\([A-Z]\) \([A-Z]\)/\1\2/g'
  Das geht deswegen schief, weil sich die Zeile während der
  Bearbeitung verkürzt.

Intern sieht das vereinfach so aus:
  F O O B A R  FOOBAR
    |-- sed merkt sich diese Postion
  FO O B A R  FOOBAR
     |-| das ist das nächste gefundene Pattern
       |-- sed merkt sich diese Postion
  FO OB A R  FOOBAR
        |-| das ist das nächste gefundene Pattern
  FO OB AR  FOOBAR
    und das kommt als Ergebnis raus

Lösung bringt hier die mehrmalige Wiederholung des sed Kommandos.
Oder als Pseudocode:
- wiederhole solange bis das Pattern nicht mehr gefunden wird

Als Skript lässt sich das dann so schreiben:

--- sample.sed ---
:x                            -- Label x
s/\([A-Z]\) \([A-Z]\)/\1\2/g  -- das auszuführende Kommando
t x                           -- wenn durch das s Kommando
                                 etwas getauscht wurde, letzte
                                 Zeile nochmal einlesen und
                                 Abarbeitung bei Label x fortsetzen
                                 ansonsten nächstes Kommando
                                 abarbeiten
s/FOOBAR/Foobar/g             -- ersetzt alle FOOBAR durch Foobar
------------------

Aufgerufen wird das dann so:
  echo "F O O B A R  FOOBAR" | sed -f sample.sed

Intern passiert dann folgendes:

Ausgangszeile
  F O O B A R  FOOBAR

nach dem ersten Durchlauf, enthält die Zeile
  FO OB AR  FOOBAR

da eine Ersetzung erfolgt ist wird mit dieser Zeile nochmal ein
Durchlauf gestartet, danach sieht die Zeile so aus
  FOOBAR  FOOBAR

da eine Ersetzung erfolgt ist ("O O" und "B A") wird mit dieser Zeile
nochmal ein Durchlauf gestartet
  FOOBAR  FOOBAR

nach diesem Durchlauf wurde keine Ersetzung mehr durchgeführt, d.h.
"t x" springt nicht mehr zum Label x und s/FOOBAR/Foobar/g wird
ausgeführt 

Da es sich um ein relativ kurzes sed-Skript handelt kann man die
Kommandos auch mit ";" getrennt auf eine Zeile schreiben und sed mit
"-e" übergeben. Bei komplexeren Skripten leidet da natürlich die
Lesbarkeit und Fehler lassen sich auch nicht mehr so einfach finden.

Hoffe noch ein wenig Licht ins Dunkel gebracht zu haben.
Frank
-- 
If code looks clumsy, it can usually be better written. Clean code
is more easily maintainable and modifiable.



Reply to: