Anzeige:
Ergebnis 1 bis 7 von 7

Thema: Komplizierte Ersetzung mit "sed"

  1. #1
    Registrierter Benutzer
    Registriert seit
    20.03.2006
    Beiträge
    180

    Komplizierte Ersetzung mit "sed"

    Hallo,

    Ich habe eine Textdatei, in der auch Zeichenketten innerhalb einem Paar geschweifter Klammern vorkommen:

    Beispiel:
    bla bla blub {Beliebiger Text in geschweiften Klammern} bla bla blub

    Ich möchte hinter JEDEM Zeichen der Zeichenkette in der geschweiften Klammer einen Doppelpunkt anbringen. Der Text außerhalb der geschweiften Klammer soll unberührt bleiben.

    Meine Versuch mit:
    sed -e 's/{[^{}]/&:/' < input > output, bzw.
    sed -e 's/[^{}]}/:&/' < input > output

    fügt nur nach dem ersten Zeichen, bzw. vor dem letzten Zeichen einen Doppelpunkt ein.

    Wer hat eine Idee, wie man das Vorhaben mit "sed" lösen kann?

    Vielen Dank im voraus.
    Gruß
    Dieter

  2. #2
    Registrierter Benutzer
    Registriert seit
    18.03.2008
    Beiträge
    22
    Hm, ich befürchte fast, dass das mit sed so nicht möglich ist. Hier mal ein paar perl-Varianten:

    Mit zwei lookaheads:
    Code:
    echo 'bla bla blub {Beliebiger Text in geschweiften Klammern} bla bla blub'|
    perl -pe 's/[^{](?=.*})(?!.*{)/$&:/g'
    Mit dem Text in curly-braces in eine eigene Variable ($b) gepackt:
    Code:
    echo 'bla bla blub {Beliebiger Text in geschweiften Klammern} bla bla blub'|
    perl -pe '$b=$1 if m|[{](.*)[}]|; $b=~s/./$&:/g; s/[{].*[}]/{$b}/'
    Oder die Zeile in durch curly-braces geteilte Felder zerteilen:
    Code:
    echo 'bla bla blub {Beliebiger Text in geschweiften Klammern} bla bla blub'|
    perl -anF'(?<={)|(?=})' -e '$F[1]=~s/./$&:/g; print @F'
    Aber kA, ich bin auch nicht so der sed-Crack, vielleicht geht das ja doch. Würde mich ehrlich gesagt auch mal interessieren.

  3. #3
    Registrierter Benutzer
    Registriert seit
    20.03.2006
    Beiträge
    180
    Ich möchte die Lösung gerne mit klassischen Unix-Bordmitteln erstellen. Da "sed" eine elegante Lösung versagt, behelfe ich mir mit in Serie geschalteten Ersetzfunktionen:

    -e 's/{[^{}]\{20,20\}/&:/g' \
    -e 's/{[^{}]\{19,19\}/&:/g' \
    -e 's/{[^{}]\{18,18\}/&:/g' \
    ...
    -e 's/{[^{}]\{3,3\}/&:/g' \
    -e 's/{[^{}]\{2,2\}/&:/g' \
    -e 's/{[^{}]\{1,1\}/&:/g' \

    Dieser Ansatz geht davon aus, dass der Text in den geschweiften Klammer jeweils nicht länger als 20 Zeichen ist; andernfalls ist er im dargestellten Sinne zu erweitern.

    Nun ja, mühsam ernährt sich bekanntlich das Eichhörnchen

    Gruß
    Dieter

  4. #4
    Registrierter Benutzer
    Registriert seit
    18.03.2008
    Beiträge
    22
    Sind diese "Unix-Boardmittel" klassisch genug?
    Code:
    line='foo bar zomg {abc def 123} baz meh asdf'
    pre_brace=`echo $line|cut -d\{ -f1`
    post_brace=`echo $line|cut -d\} -f2`
    brace=`echo $line|sed -e 's!.*{\(.*\)}.*!\1!'`
    brace=`echo $brace|sed -e 's/./&:/g'`
    echo "${pre_brace}{${brace}}${post_brace}"
    Sollte bourne-shell kompatibel sein. (Wenn auch imho sehr unelegant, aber immernoch attraktiver als dein "Vorschlag". awk hab ich bewusst ausgelassen. (Nicht klassisch genug? kA))
    Ich weiß auch nicht inwiefern du dich vor perl sträubst. Mit einem kleinen (non-cli) Skript könnte man das recht einfach und vor allem auch les-/nachvollziehbar erledigen. Aber whatever floats your boat.

  5. #5
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    das folgende Monstrum ist sicher noch nicht 100% perfekt (dazu müsste man mal mit ein paar wildgewordenen Daten testen), aber zur Veranschaulichung meiner Idee sollte es reichen. Ich präsentiere erstmal ein funktionierendes Beispiel und nehme es dann auseinander (wegen der Tradition habe ich auch auf erweiterte Regex verzichtet - macht den Code nicht unbedingt schöner, sollte aber mit jedem Unix-sed laufen):
    Code:
    jan@jack:~/tmp> echo -e "12345{678abc}90\n12{34}56{7}890" | \
    sed ': X;s/\({[^:{}]*\)\([^:{}]\)\([^:{}]\)/\1\2:\3/g;t X;s/\([^:{}]\)}/\1:}/g'
    12345{6:7:8:a:b:c:}90
    12{3:4:}56{7:}890
    Der echo gibt einfach erstmal 2 Zeilen mit verschiedenen Varianten Deiner Aufgabe aus. Auf gehts in die sed-Interna:
    Code:
    jan@jack:~/tmp> echo -e "12345{678abc}90\n12{34}56{7}890" | \
    > sed ': X # Sprungmarke (Label) mit dem Namen "X" definieren
    > s/\({[^:{}]*\)\([^:{}]\)\([^:{}]\)/\1\2:\3/g # ersetzt diese Stellen: 
    > # ("{" & beliebig viele Zeichen ausser ":{}") = Puffer1
    > # & (1 beliebiges Zeichen ausser ":{}") = Puffer2
    > # & (1 beliebiges Zeichen ausser ":{}") = Puffer3
    > # durch: Puffer1 & Puffer2 & ":" & Puffer3
    > t X # wenn die letzte Ersetzung erfolgreich war, dann zurueck zum
    > # Label "X"
    > s/\([^:{}]\)}/\1:}/g' # zum Schluss nach dem letzten Zeichen vor "}"
    > # ein ":" einfügen
    12345{6:7:8:a:b:c:}90
    12{3:4:}56{7:}890
    Der Trick beruht also darauf, eine Schleife zu produzieren, in der alle 2-Zeichen-Konstruktionen, die nach einem "{" folgen und noch keinen ":" enthalten, nacheinander ersetzt werden. Der Sonderfall für das letzte Zeichen vor dem "}" wird separat behandelt. Der Rücksprung zum Label "X" wird nur dann ausgeführt, wenn das s/.../.../-Konstrukt mindestens eine Ersetzung vorgenommen hat.

    Jan
    Geändert von jan61 (20-05-2008 um 01:59 Uhr)

  6. #6
    Registrierter Benutzer
    Registriert seit
    20.03.2006
    Beiträge
    180
    Wiener Kind (WeenerChild),

    vielen Dank für Deinen Vorschlag. Ich sträube mich nicht gegen Perl, ich wollte lediglich eine reine Unix-Lösung.



    Jan61,

    vielen Dank für Deinen Vorschlag.

    Gruss
    Dieter

  7. #7
    Registrierter Benutzer Avatar von rais
    Registriert seit
    18.07.2005
    Beiträge
    5.862

    ot

    Zitat Zitat von DieterH Beitrag anzeigen
    Wiener Kind
    hmm, so es denn eine geographische Anspielung ist, würde ich `Weener' weg von der Donau, dafür dichter an der Ems ansiedeln.;-)

    MfG
    Rainer
    There's nothing a good whack with a hammer won't fix!

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •