RegEx via Kommandozeile
Sven Rautenberg
- perl
Moin!
Ich hab leichte Probleme, einem Perl-Script meine Wünsche hinsichtlich eines regulären Ausdrucks verständlich zu machen.
Ausgangslage: Ich habe einen Batzen HTML-Dateien, die ein paar unerwünschte Formatierungen drin haben. Diese Formatierungen lassen sich im Prinzip alle recht schön mit regulären Ausdrücken suchen und ersetzen.
Dazu habe ich mir von Ulli Meybohm sein Skript "rxr" geholt. Das Skript nimmt als Kommandozeilenparameter einen oder zwei Parameter entgegen, um damit den regulären Ausdruck zu füttern. Das Thema "Escapen von für die Kommandozeile relevanten Zeichen" habe ich schon hinter mir - die Ausdrücke strotzen jetzt vor Backslashes.
Das Problem:
find * | grep ".HTM" | rxr <H3>(.*?)<\/H3> <p><strong>$1</strong></p>
Diese Kommandozeile soll z.B. nach allen Überschriften <h3> suchen diese in <p><strong></strong></p> umwandeln. Das Problem ist: Der ersetzte Ausdruck lautet wortwörtlich <p><strong>$1</strong></p> - der Inhalt der ersten Klammer wird leider nicht wieder eingesetzt.
Ich hab schon so einiges probiert. Ich bin mir relativ sicher, dass ich $1 nehmen muß - \1 habe ich aber auch schon probiert. Ich lasse mir auch ausgeben, was das Skript als Werte für die Ersetzung übergeben kriegt - das ist alles einwandfrei:
print "Replacing Operation: s/$searchfor/$replacewith/igse\n";
ergibt:
Replacing Operation: s/<H3>(.*?)</H3>/<p><strong>$1</strong></p>/igse
bei oben angegebener Kommandozeile.
Die eigentliche "Arbeitszeile" lautet:
$fullline =~ s/$searchfor/$replacewith/igse;
(Das restliche Skript ist unter http://homepages.fh-giessen.de/~hg8444/src/rxr.gz zu finden.)
$fullline enthält die jeweilige komplette HTML-Datei, in $searchfor steht der erste Parameter, in $replacewith der zweite Parameter.
Vielleicht kann mir ja ein Perl-Regex-Experte verraten, wie ich es schaffe, die Klammervariablen per Kommandozeilenparameter in den regulären Ausdruck einzuschleusen. Ich habe leider keine guten Ideen mehr.
Alternativen wären natürlich auch nicht schlecht. Ich hatte kurz über sed nachgedacht, aber der muß ja auch irgendwie alle Dateien einzeln serviert kriegen - also besteht wieder ein Aufwand, das zu programmieren...
- Sven Rautenberg
Moin Moin !
find * | grep ".HTM" | rxr <H3>(.*?)<\/H3> <p><strong>$1</strong></p>
Ähhhh....
Willst Du die Klammern um .*? für Perl oder die Shell escapen ? Für Perl müßtest Du die Backslashe auch noch escapen [ \(.*?\) ], das willst Du aber wohl kaum. Und die Shell sollte die Backslashes nicht wirklich brauchen, oder ?
Alexander
Moin!
find * | grep ".HTM" | rxr <H3>(.*?)<\/H3> <p><strong>$1</strong></p>
Ähhhh....
Willst Du die Klammern um .*? für Perl oder die Shell escapen ? Für Perl müßtest Du die Backslashe auch noch escapen [ \(.*?\) ], das willst Du aber wohl kaum. Und die Shell sollte die Backslashes nicht wirklich brauchen, oder ?
Doch, die Shell braucht die Backslashes. Denn mit runden Klammern startet man ansonsten eine Subshell, in der man gewisse Dinge ausführen lassen kann. Das will ich garantiert nicht.
Von den Backslashes her gesehen kommt in Perl alles so an, wie ich es denke, dass es gut ist. Und die runden Klammern sind auch nicht das Problem - die funktionieren scheinbar, denn es wird die gesamte <h3>...</h3> ersetzt. Nur eben nicht durch <p><strong>...alte Überschrift...</strong></p>, sondern durch <p><strong>$1</strong></p>.
Deswegen meine Vermutung, dass Perl zwar reguläre Ausdrücke durch Variablen befüllen lassen kann, aber dort selbst keine Variablen enthalten sein können. Andererseits kann ich mir das nicht so recht vorstellen.
- Sven Rautenberg
Moin Moin !
Und die Shell sollte die Backslashes nicht wirklich brauchen, oder ?
Doch, die Shell braucht die Backslashes. Denn mit runden Klammern startet man ansonsten eine Subshell, in der man gewisse Dinge ausführen lassen kann. Das will ich garantiert nicht.
Aber nur, wenn Du auf Single Quotes um die Argumente für rxr verzichtest -- wir reden doch über UNIXe, oder ?
Dann wären übrigens * und ? auch noch zu escapen.
Geht das folgende ?
find * | grep ".HTM" | rxr '<H3>(.*?)</H3>' '<p><strong>$1</strong></p>'
Alexander
Hi Sven!
Von den Backslashes her gesehen kommt in Perl alles so an, wie ich es denke, dass es gut ist. Und die runden Klammern sind auch nicht das Problem - die funktionieren scheinbar, denn es wird die gesamte <h3>...</h3> ersetzt. Nur eben nicht durch <p><strong>...alte Überschrift...</strong></p>, sondern durch <p><strong>$1</strong></p>.
Ich kann mir nicht vorstellen das Du da Erfolg haben wirst, denn wenn das ginge, das Du einem PERL-Script echten PERL-Code übergeben könntest, dann wäre ja absolut gar nichts mehr sicher.
Wenn man das ganze mal auf das Kernproblem reduziert(zumindest soweit ich das einschätzen kann), dann müßte man erstmal folgends Scritp ans laufen bekommen:
#!/usr/bin/perl
$a="Hat geklappt!";
$b=$ARGV[0];
print "b:";
print $b;
print "\n";
Wenn Du jetzt das Script mit "scriptname.pl $a" startest, das wäre ja vergleichbar mit dem was Du da versucht hast. Wenn es "funktionieren Würde müßte als Ausgabe der Variable $a rauskommen, aber ich glaueb nicht das das klappt, ich jedenfalls habe es nicht geschafft. Die einzige Möglichkeit die mir eingefallen wäre ist eval. Du könntest Deinen searchstring im Script noch selbst parsen, also bei jedem /$\w+/ oder so ähnlich zerteilen, den/die ausgeschnittenen Teil(e) durch eval schicken und danach wieder zusammensetzen. Aber vielleicht zählt das ja auch nicht für RegEx, da gelten ja durchaus eigene Gesetze, habe sonst keine Ahnung.
Viele Grüße
Andreas
Hallo Andreas,
[... Theorien, warum das gewuenschte so nicht funktioniert ...]
Warum schreibe ich eigentlich meine Beitraege? Aus
[pref:t=32570&m=176419]:
|Sicher, das Perl-Script kriegt einen String. Da fehlt wohl
|ein 'ee', wenn es unbedingt mit Back-References gehen soll.
|Dann musst du aber auch "<p><strong>".$1."</p></strong>"
|schreiben. Mit dem doppelten 'e' wuerde halt der
|Ersetzungs-String ausgefuehrt (evaluiert).
Gruesse,
CK
Hallo!
Warum schreibe ich eigentlich meine Beitraege? Aus
[pref:t=32570&m=176419]:|Sicher, das Perl-Script kriegt einen String. Da fehlt wohl
|ein 'ee', wenn es unbedingt mit Back-References gehen soll.
|Dann musst du aber auch "<p><strong>".$1."</p></strong>"
|schreiben. Mit dem doppelten 'e' wuerde halt der
|Ersetzungs-String ausgefuehrt (evaluiert).
Oh, das hatte ich im ersten Moment dann doch nicht richtig verstanden, sorry! Hatte das eigentliche Problem erst später erkannt. Aber Danke für den Hinweis.
Grüße
Andreas
Hallo Sven,
Dazu habe ich mir von Ulli Meybohm sein Skript "rxr"
geholt.
Ts, ts, ts :) Dafuer ist doch find wunderbar geeignet:
find . -name "*.htm" -exec perl -pi -e 's!muster!replace!sg' {} ;
find * | grep ".HTM" | rxr <H3>(.*?)<\/H3> <p><strong>$1</strong></p>
find . -name "*.HTM" -exec rxr '<H3>(.*?)</H3>' '<p><strong>$1</strong></p>'
wenn es denn unbedingt 'rxr' sein muss. Ansonsten:
find . -name "*.HTM" -exec perl -pi -e 's!<H3>(.*?)</H3>!<p><strong>$1</strong></p>!sg'
Diese Kommandozeile soll z.B. nach allen Überschriften
<h3> suchen diese in <p><strong></strong></p> umwandeln.
Das Problem ist: Der ersetzte Ausdruck lautet wortwörtlich
<p><strong>$1</strong></p> - der Inhalt der ersten Klammer
wird leider nicht wieder eingesetzt.
Sicher, das Perl-Script kriegt einen String. Da fehlt wohl
ein 'ee', wenn es unbedingt mit Back-References gehen soll.
Dann musst du aber auch "<p><strong>".$1."</p></strong>"
schreiben. Mit dem doppelten 'e' wuerde halt der
Ersetzungs-String ausgefuehrt (evaluiert).
Gruesse,
CK
Hallo Sven,
find . -name "*.HTM" -exec rxr '<H3>(.*?)</H3>' '<p><strong>$1</strong></p>'
[...]
find . -name "*.HTM" -exec perl -pi -e 's!<H3>(.*?)</H3>!<p><strong>$1</strong></p>!sg'
Sorry, kleiner Fehler:
find . -name "*.HTM" -exec cat {} | rxr '<H3>(.*?)</H3>' '<p><strong>$1</strong></p>' ;
sowie
find . -name "*.HTM" -exec perl -pi -e 's!<H3>(.*?)</H3>!<p><strong>$1</strong></p>!sg' {} ;
Gruesse,
CK
Moin!
find . -name "*.HTM" -exec cat {} | rxr '<H3>(.*?)</H3>' '<p><strong>$1</strong></p>' ;
sowie
find . -name "*.HTM" -exec perl -pi -e 's!<H3>(.*?)</H3>!<p><strong>$1</strong></p>!sg' {} ;
Ich werd's morgen ausprobieren (jetzt ist erstmal Feierabend). Spontan wollte die zweite Variante allerdings nicht funktionieren.
Zumindest hab' ich neue Ideen. :)
- Sven Rautenberg
Hallo Sven,
Ausgangslage: Ich habe einen Batzen HTML-Dateien, die ein paar unerwünschte Formatierungen drin haben.
(...)
Diese Kommandozeile soll z.B. nach allen Überschriften <h3> suchen diese in <p><strong></strong></p> umwandeln.
Aus purer Neugierde: Wieso das denn? Sind die Elementinhalte dann doch keine Überschriften?
Moin Moin !
Aus purer Neugierde: Wieso das denn? Sind die Elementinhalte dann doch keine Überschriften?
Vielleicht hat ihm ja jemand ein "paar" mit einem Klickibunti-HTML-Verwurster gebastelte Dateien in den Bauch gedrückt, und er versucht jetzt zu retten, was noch zu retten ist.
Alexander
Moin!
Aus purer Neugierde: Wieso das denn? Sind die Elementinhalte dann doch keine Überschriften?
Es liegt einfach daran, dass die Dateien einem CMS übergeben werden (Reddot, um genau zu sein). Und dort konnte ich den Redakteuren leider keine Möglichkeit freischalten, im Text echte Überschriften zu definieren, weil damit gleichzeitig die Möglichkeit entsteht, <font size="..."> einzufügen. Und das will ich erst recht nicht.
Also besteht nur die Möglichkeit, Text fett zu machen, was dann wie eine Zwischenüberschrift aussieht - aber natürlich keine ist. Ist eben ein Kompromiß - wie vieles, was man in Reddot macht.
Ein Beispiel: Reddot haut eine Signatur in Form eines Meta-Tags in jede generierte Seite - und das geschieht in einer absolut dummen und hirnrissigen Form (leicht gekürzt):
<META NAME="GENERATOR" CONTENT="... generated by RedDot 4.5 (SP2)..."/>
Schwachsinn 1: Die XHTML-Form. Reddot hat sonst nirgends eine Ahnung von XHTML - aber im Meta-Tag basteln sie die zu HTML inkompatible Form mit rein. Der Validator bemängelt zu Recht, dass vor dem abschließenden Slash kein Leerzeichen ist, wenn man nach HTML validiert.
Schwachsinn 2: Wenn man schon XHTML reinschreibt, dann doch bitteschön _Kleinbuchstaben_ als Elementbezeichner! XHTML ist schließlich case-sensitiv, <META> ist etwas anderes als <meta>. Aber das scheint bei Reddot noch keiner gemerkt zu haben, denn alle von _Reddot_ generierten (und nicht in Templates vorher festgelegten) Elemente sind in Großbuchstaben: <A>, <IMG>, ...
Vielleicht hat ihm ja jemand ein "paar" mit einem Klickibunti-HTML-Verwurster gebastelte Dateien in den Bauch gedrückt, und er versucht jetzt zu retten, was noch zu retten ist.
<FONT> etc. entferne ich schon reichlich aus den Seiten. ;-)
- Sven Rautenberg
Hallo Sven,
Es liegt einfach daran, dass die Dateien einem CMS übergeben werden (Reddot, um genau zu sein).
Ach. CMSe - da hätte ich auch gleich draufkommen können. Habe mich schließlich schon genug mit ähnlichem rumgeplagt. Mein Beileid hast Du :-)