PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : sed: subpatterns nochmals substituieren?



McFraggle
28-05-2009, 15:26
Hallo!
Ich habe eine etwas kniffligere Anforderung an sed (oder awk?), die meinen derzeitigen Horizont auch vier Std. nächtlichem googlen übersteigt.

Eingabe:
In einem Text können beliebig verteilt Worte folgender genügsamen regulären Sprache vorkommen:

<a>.*</a>
Also etwa

...bla bla bla <a>foo.bar.baz</a> bla bla...

Ausgabe:
Daraus soll gemacht werden:

...bla bla bla <a href="foo/bar/baz.html">foo.bar.baz</a> bla bla...

Das Problem besteht darin, dass ein Subpattern einmal in einer veränderten Variante eingesetzt werden muss (Punkte durch Slashes substituiert).

Das Resultat

...bla bla bla <a href="foo.bar.baz.html">foo.bar.baz</a> bla bla...
ist mit sed recht einfach durch

s/<api>\(.*\)<\/api>/<a href="\1.html">\1<\/a>/g
zu erreichen.
Auf die erste Einsetzung des Musters \1 müsste nochmal eine Substitution angesetzt werden, welche die Punkte durch Slashes ersetzt. Ich habe jedoch keine Ahnung, wie ich das erreichen kann.

Ich bin für jede Idee dankbar! :)

ContainerDriver
28-05-2009, 16:32
Hallo,

wenn es nur um die Lösung der Aufgabe geht, dann würde ich sed einfach nochmal drüber laufen lassen (natürlich Such-/Ersetzungsmuster anpassen) oder zwei Ersetzungsausdrücke angeben ("s/.../;s/.../").

Gruß, Florian

McFraggle
28-05-2009, 17:08
Hallo Florian,
hmmm.... wie sähe dann das zweite Kommando aus? Ich habe auch kurz daran gedacht, aber den Gedanken sofort wieder verworfen, da ich nicht glaube, dass sich das mit sed noch lösen lässt. Andere a-Tags dürfen davon ja nicht beeinträchtigt werden. Ich finde die Stellen also niemals wieder! :D Abgesehen davon müssten auch die zwei Varianten (Wert von href und Text) unterschieden werden können und gleichzeitig Punkte durch Slashes substituiert werden (nur nicht der letzte von .html).

Ich wüsste nicht wie das gehen soll.

Grüße,
Daniel

jan61
28-05-2009, 19:27
Moin,

zuerst eine Warnung: Das Folgende funktioniert nur unter der Voraussetzung, dass das Muster "<api>...</api>" nur einmal pro Zeile auftaucht. Ich habe es auch nur mit einer Beispielzeile getestet, also gründlich prüfen!

Die sed-Kommandofolge habe ich in ein Script ausgelagert, damit es übersichtlicher ist:

jan@jack:~/tmp> cat foobar.sed
# Ersetzung wie im Original, aber beginnendes "<api" stehen lassen
# damit haben wir noch einen Anhaltspunkt, wo zu ersetzen ist
s/<api>(.*)<\/api>/<api href="\1.html">\1<\/a>/
# Sprungmarke "L" definieren
: L
# Ersetzen des letzten, zwischen `<api href="` und `.html">` liegenden
# . durch /
s/(.*<api href="[^"]+)\.(.+\.html">)/\1\/\2/
# wenn Ersetzung erfolgte: zurueck zur Sprungmarke "L"
t L
# keine Ersetzung mehr: Jetzt `<api href="` durch `<a href="` ersetzen
s/<api href="/<a href="/
jan@jack:~/tmp> echo 'bla bla <a href="a/b/c.html">a.b.c</a> bla <api>foo.bar.baz</api> bla bla' | \
> sed -rf foobar.sed
bla bla <a href="a/b/c.html">a.b.c</a> bla <a href="foo/bar/baz.html">foo.bar.baz</a> bla bla
Wie Du siehst, habe ich die "-r"-Option des sed genutzt, damit wird das nicht so ein \-Verhau.

Jan

Sid Burn
29-05-2009, 09:41
Zwar nicht sed sondern Perl, aber vielleicht ist es ja eine Option.


echo '...bla bla bla <a>foo.bar.baz</a> bla <a>heise.de</a>bla...' | perl -wpe 's{<a>(.*?)</a>}{($o,$n)=($1,$1);$n=~s#[.]#/#g; qq{<a href="$n">$o</a>} }ge'

Kann auch ohne Probleme mit mehrere <a> auf einer zeile umgehen. Wenn das öffnen <a> und das schließen </a> auf unterschiedlichen zeilen steht dann geht es allerdiengs nicht. (Könnte man aber anpassen).


damit wird das nicht so ein \-Verhau.
Auch bei sed kann man andere Begrenzer als / wählen.

jan61
29-05-2009, 18:19
Moin,


Auch bei sed kann man andere Begrenzer als / wählen.

Da das in diesem Fall ganze 2 (in Worten zwei) Backslashes einspart, habe ich drauf verzichtet. Wichtiger war mir die Übersichtlichkeit - d. h. Gruppierungen durch Klammern besser als solche erkennbar zu machen.

Jan