Bernte
Anmeldungsdatum: 4. Januar 2007
Beiträge: Zähle...
|
Hi! Ich versuche gerade, ein großes LaTeX-Projekt ein wenig aufzuräumen. So sieht es zur Zeit aus: Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} \korrektur{\emph{blau}}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann. Und so soll es aussehen:
Schlümpfe sind im allgemeinen \emph{blau}, wie man mithilfe eines Lakmus-Tests schnell rausfinden kann. Bis jetzt habe ich es nur geschafft, einfache Textausdrücke zu korrigieren:
sed -i 's/mit Hilfe/mithilfe/g' *.tex Die verschachtelten Klammern hingegen bekomme ich nicht hin. Ich habe irgendwo gelesen, dass sed sowas nicht kann, weil es kein regulärer Ausdruck ist. Kann awk das vielleicht machen?
|
xubuntufriese
Anmeldungsdatum: 3. Mai 2014
Beiträge: 340
|
$ cat schlumpf.txt
Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} \korrektur{\emph{blau}}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
$ sed -r 's/\\geloescht\{\\emph\{grün\}\} \\korrektur\{(\\emph\{blau\})\}/\1/g' schlumpf.txt
Schlümpfe sind im allgemeinen \emph{blau}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann. \geloescht{\emph{grün}} \korrektur{\emph{blau}} Die "\" und "{}" sind Metazeichen, deshalb musst Du sie escapen. Suchausdruck:
\\geloescht\{\\emph\{grün\}\} \\korrektur\{(\\emph\{blau\})\} Der Teil in den Klammern kann als "\1" wieder abgerufen werden, also ist "\\emph\{blau\}" auch die Ersetzung.
|
Bernte
(Themenstarter)
Anmeldungsdatum: 4. Januar 2007
Beiträge: 35
|
Danke, aber so war das Beispiel nicht gemeint. Ich will in
bla bla \korrektur{beliebiger {} {Inhalt {mit}} Klammern} blub blub
die Umgebung
\Korrektur{...}
loswerden, sodass ich
bla bla beliebiger {} {Inhalt {mit}} Klammern blub blub
erhalte.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
Bernte schrieb:
Die verschachtelten Klammern hingegen bekomme ich nicht hin. Ich habe irgendwo gelesen, dass sed sowas nicht kann, weil es kein regulärer Ausdruck ist.
Genau. Dafür muss man ein Werkzeug haben, das mehr als nur die regulären Sprachen erkennen kann.
Kann awk das vielleicht machen?
Soweit ich weiß nicht. Ich habe mal einen kurzen Blick in die Doku von gawk geworfen und keine Anhaltspunkte gefunden, dass das damit geht. Du hast - grob gesagt - folgende Möglichkeiten:
Du nutzt einen Parser-Generator, der kontextfreie Sprachen erkennen kann (yacc , bison , antlr usw.). Du nutzt eine Sprache mit einer erweiterten Regex-Engine (Perl, Ruby).
Die erste Variante ist recht aufwändig - die zweite weniger, auch, wenn es einen Moment braucht zu verstehen, wie das funktioniert. Ich würde natürlich immer Ruby nehmen, da ich Perl generell für schwer lesbar und dessen Regex-Engine für total durchgeknallt halte (man kann Perl-Code in den Matching-Prozess einbetten). Schau mal auf Punkt 9 der Doku von Oniguruma. Dann habe ich mal ein kleines Beispielprogramm geschrieben, das erkennt, ob Klammern in einer Datei balanciert sind. Ich meine, ich hätte noch irgendwo anders ein Beispiel, finde es aber gerade nicht. Gute Nacht! robert
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
Ed gibt natürlich auch noch die dritte Möglichkeit, das Parsen der Klammernpaare selbst zu implementieren.
|
Bernte
(Themenstarter)
Anmeldungsdatum: 4. Januar 2007
Beiträge: 35
|
Hi Robert! rklm schrieb:
Schau mal auf Punkt 9 der Doku von Oniguruma. Dann habe ich mal ein kleines Beispielprogramm geschrieben, das erkennt, ob Klammern in einer Datei balanciert sind. Ich meine, ich hätte noch irgendwo anders ein Beispiel, finde es aber gerade nicht.
Vielen Dank für das Beispielprogramm. Das an meine Bedürfnisse anzupassen sollte ja kein allzu großes Problem darstellen. Da werde ich mich morgen gleich mal ransetzen, wenn ich etwas Zeit hab. Dann hab ich auch mal einen Anlass, mir ein bisschen Ruby anzugucken 😉 Gruß, Bernd
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7658
|
Solang sich die Klammern alle auf einer Zeile abspielen kannst du auch mit sed ... ähm ... kreativ werden. Die Frage ist hier wie so oft, musst du da wirklich eine Lösung stricken die alle Möglichkeiten der TeX Sprache abdeckt, oder hat dein Dokument Randbedingungen mit der sich das ziemlich einschränken läßt. $ ./korrektur.sh beispiel.txt ausgabe.txt
$ diff -u beispiel.txt ausgabe.txt
--- beispiel.txt 2014-11-28 13:40:41.812056802 +0100
+++ ausgabe.txt 2014-11-28 13:42:07.594652089 +0100
@@ -1,4 +1,4 @@
-Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} \korrektur{\emph{blau}}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
+Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} \emph{blau}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
Und so soll es aussehen:
@@ -12,7 +12,7 @@
Danke, aber so war das Beispiel nicht gemeint. Ich will in
-bla bla \korrektur{beliebiger {} {Inhalt {mit}} Klammern} blub blub
+bla bla beliebiger {} {Inhalt {mit}} Klammern blub blub
die Umgebung korrektur.sh: #!/bin/bash
truncate -s 0 korrektur.sed
for i in {001..999}
do
echo 's@\{([^{}]*)\}@###A:'$i'###\1###B:'$i'###@' >> korrektur.sed
done
for i in {001..999}
do
echo 's@\\korrektur###A:'$i'###(.*)###B:'$i'###@\1@' >> korrektur.sed
done
for i in {001..999}
do
echo 's@###A:'$i'###(.*)###B:'$i'###@{\1}@' >> korrektur.sed
done
sed -r -f korrektur.sed < "$1" > "$2" Die Idee hier ist, immer das innerste Klammernpaar durch einen eindeutigen (nummerierten) Platzhalter zu ersetzen, dann anschließend die so zugeordnete Klammer zu entfernen, und am Ende alle Platzhalter wieder zu normalen Klammern zu machen.
|
xubuntufriese
Anmeldungsdatum: 3. Mai 2014
Beiträge: 340
|
rklm schrieb: Bernte schrieb:
Die verschachtelten Klammern hingegen bekomme ich nicht hin. Ich habe irgendwo gelesen, dass sed sowas nicht kann, weil es kein regulärer Ausdruck ist.
Genau. Dafür muss man ein Werkzeug haben, das mehr als nur die regulären Sprachen erkennen kann.
Kann awk das vielleicht machen?
Soweit ich weiß nicht. Ich habe mal einen kurzen Blick in die Doku von gawk geworfen und keine Anhaltspunkte gefunden, dass das damit geht.
Solange sich alles auf einer Zeile abspielt - kein Problem. Falls sich diese Konstrukte auch über mehr als 1 Zeile hinziehen gibt es auch Möglichkeiten (mittels getline die nächste Zeile holen). Dann muss man entscheiden, ob das was in mehreren Zeilen steht in mehreren Zeilen bleiben soll, oder zu einer Zeile zusammengefügt werden soll. Folgendes Beispiel funktioniert nur für "\geloescht{...}" (fliegt ganz raus) und "\korrektur{...}" (... bleibt erhalten):
$ cat klammern_weg.awk
function loesch(line, rstart, rlength) {
n = split(line, d_a, "")
b_open=1
for( i=rstart+rlength; i<=n; i++ ) {
if( d_a[i]=="}")
b_open--
if( b_open==0 )
break
if( d_a[i]=="{")
b_open++
}
x = 1
if( d_a[i+1]==" " )
x++
return substr(line, 1, rstart-1) substr(line, i+x)
}
function korrektur(line, rstart, rlength) {
n = split(line, d_a, "")
b_open=1
b_val=""
for( i=rstart+rlength; i<=n; i++ ) {
if( d_a[i]=="}")
b_open--
if( b_open==0 )
break
if( d_a[i]=="{")
b_open++
b_val = b_val d_a[i]
}
return substr(line, 1, rstart-1) b_val substr(line, i+1)
}
{
while($0 ~ /\\(geloescht|korrektur)\{/) {
if( match($0, /\\geloescht\{/) ) {
$0 = loesch($0, RSTART, RLENGTH)
}
if( match($0, /\\korrektur\{/) ) {
$0 = korrektur($0, RSTART, RLENGTH)
}
}
print $0
}
$ cat schlumpf.txt
Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} \korrektur{\emph{blau}}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
bla0 bla0 \korrektur{beliebiger0 {} {Inhalt0 {mit0}} Klammern0} blub0 blub0
bla1 bla1 beliebiger1 {} {Inhalt1 {mit1}} Klammern1 blub1 blub1 -> war schon fertig
bla2 bla2 \korrektur{beliebiger2 {} {Inhalt2 {mit2}} Klammern2} blub2 blub2
bla3 bla3 \korrektur{beliebiger3 {} {Inhalt3 {mit3}} Klammern3} blub3 blub3
bla4 bla4 \geloescht{\foo4{bar4}} \korrektur{beliebiger4 {} {Inhalt4 {mit4}} Klammern4} blub4 blub4
bla5 bla5 \geloescht{\foo51{bar51}} uuups \geloescht{\foo52{bar52}} blub5 blub5
bla6 bla6 \korrektur{\foo61{bar61}} uuups \korrektur{\foo62{bar62}} blub6 blub6
$ gawk -f klammern_weg.awk schlumpf.txt
Schlümpfe sind im allgemeinen \emph{blau}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
bla0 bla0 beliebiger0 {} {Inhalt0 {mit0}} Klammern0 blub0 blub0
bla1 bla1 beliebiger1 {} {Inhalt1 {mit1}} Klammern1 blub1 blub1 -> war schon fertig
bla2 bla2 beliebiger2 {} {Inhalt2 {mit2}} Klammern2 blub2 blub2
bla3 bla3 beliebiger3 {} {Inhalt3 {mit3}} Klammern3 blub3 blub3
bla4 bla4 beliebiger4 {} {Inhalt4 {mit4}} Klammern4 blub4 blub4
bla5 bla5 uuups blub5 blub5
bla6 bla6 \foo61{bar61} uuups \foo62{bar62} blub6 blub6
|
Bernte
(Themenstarter)
Anmeldungsdatum: 4. Januar 2007
Beiträge: 35
|
frostschutz schrieb: Solang sich die Klammern alle auf einer Zeile abspielen kannst du auch mit sed ... ähm ... kreativ werden.
xubuntufriese schrieb: Solange sich alles auf einer Zeile abspielt - kein Problem. Falls sich diese Konstrukte auch über mehr als 1 Zeile hinziehen gibt es auch Möglichkeiten (mittels getline die nächste Zeile holen). Dann muss man entscheiden, ob das was in mehreren Zeilen steht in mehreren Zeilen bleiben soll, oder zu einer Zeile zusammengefügt werden soll.
Ihr habt recht, zeilenweise reicht mir tatsächlich. Ich danke euch vielmals fürs komplett fertig programmieren! Ich werde wahrscheinlich xubuntufrieses Lösung verwenden, auch wenn ich von der Eleganz von frostschutzes Ansatz mit sed ganz hin und weg bin 😉
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
Bernte schrieb:
Vielen Dank für das Beispielprogramm. Das an meine Bedürfnisse anzupassen sollte ja kein allzu großes Problem darstellen. Da werde ich mich morgen gleich mal ransetzen, wenn ich etwas Zeit hab. Dann hab ich auch mal einen Anlass, mir ein bisschen Ruby anzugucken 😉
Was hat denn Deine Beschäftigung mit Ruby ergeben? Ich habe eine Lösung mit erweiterten Regex in Ruby gefunden, die m.E. deutlich eleganter (und auch dramatisch kürzer) ist als die bisher gesehenen. 😉
|
Bernte
(Themenstarter)
Anmeldungsdatum: 4. Januar 2007
Beiträge: 35
|
Was hat denn Deine Beschäftigung mit Ruby ergeben? Ich habe eine Lösung mit erweiterten Regex in Ruby gefunden, die m.E. deutlich eleganter (und auch dramatisch kürzer) ist als die bisher gesehenen. 😉
Ich hab ein bisschen im Quelltext von deinem Beispiel rumgestochert und dann beschlossen, dass ich das lieber lassen sollte. Die Syntax von Ruby ist mir sehr fremd, und ich könnte mich jetzt super damit beschäftigen, sie zu lernen, statt mich um meine eigentliche Arbeit zu kümmern 😉
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
Bernte schrieb:
Ich hab ein bisschen im Quelltext von deinem Beispiel rumgestochert und dann beschlossen, dass ich das lieber lassen sollte. Die Syntax von Ruby ist mir sehr fremd,
Dabei hat Ruby doch so eine klare Syntax. ☺
und ich könnte mich jetzt super damit beschäftigen, sie zu lernen, statt mich um meine eigentliche Arbeit zu kümmern 😉
☺ Na, dann lasse ich die Katze mal aus dem Sack: $ ruby -pe '$_.gsub!(/\\korrektur\{((?:[^{}]|\{\g<1>\})*)\}/, "<\\1>")' schlumpf.txt
Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} <\emph{blau}>, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
bla0 bla0 <beliebiger0 {} {Inhalt0 {mit0}} Klammern0> blub0 blub0
bla1 bla1 beliebiger1 {} {Inhalt1 {mit1}} Klammern1 blub1 blub1 -> war schon fertig
bla2 bla2 <beliebiger2 {} {Inhalt2 {mit2}} Klammern2> blub2 blub2
bla3 bla3 <beliebiger3 {} {Inhalt3 {mit3}} Klammern3> blub3 blub3
bla4 bla4 \geloescht{\foo4{bar4}} <beliebiger4 {} {Inhalt4 {mit4}} Klammern4> blub4 blub4
bla5 bla5 \geloescht{\foo51{bar51}} uuups \geloescht{\foo52{bar52}} blub5 blub5
bla6 bla6 <\foo61{bar61}> uuups <\foo62{bar62}> blub6 blub6 Wenn man den Ausdruck etwas auseinander zieht, sieht man besser, was passiert (Man kann den Ausdruck übrigens genau so in ein Ruby-Programm schreiben und sogar mit Kommentaren versehen, was der Lesbarkeit unheimlich hilft): | /
\\korrektur\{
(
(?:
[^{}]
| \{ \g<1> \}
)*
)
\}
/x
|
Zeile 2 und 9 sollten klar sein. Zeile 3 bis 8 sind die Capturing Group 1, die auch für die Ersetzung genutzt wird. Die Gruppe in Zeile 4 bis 7 matched eine beliebig lange Folge von entweder Nicht-Klammern (Zeile 5) oder einem Paar geschweifte Klammern mit einem rekursiven Aufruf von Gruppe 1 (Zeile 6). Das bedeutet, anders als die Rückreferenz auf eine Gruppe, die genau denselben Text erkennt, wird hier rekursiv der Matchausdruck angewendet. Es ist also wieder eine Folge von Nicht-Klammern oder geklammerter Folge... usw. Der Rest der Kommandozeile oben ist schnell erklärt: -p packt das Skript in eine Schleife, die alle Zeilen nach $_ liest und hinterher $_ ausgibt. -e gibt das Skript auf der Kommandozeile an. Hier noch der diff : $ ruby -pe '$_.gsub!(/\\korrektur\{((?:[^{}]|\{\g<1>\})*)\}/, "<\\1>")' schlumpf.txt \
> | diff -U2 schlumpf.txt -
--- schlumpf.txt 2014-11-30 22:28:14.168133097 +0100
+++ - 2014-12-02 18:58:40.085781256 +0100
@@ -1,9 +1,9 @@
-Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} \korrektur{\emph{blau}}, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
-bla0 bla0 \korrektur{beliebiger0 {} {Inhalt0 {mit0}} Klammern0} blub0 blub0
+Schlümpfe sind im allgemeinen \geloescht{\emph{grün}} <\emph{blau}>, wie man mit Hilfe eines Lakmus-Tests schnell rausfinden kann.
+bla0 bla0 <beliebiger0 {} {Inhalt0 {mit0}} Klammern0> blub0 blub0
bla1 bla1 beliebiger1 {} {Inhalt1 {mit1}} Klammern1 blub1 blub1 -> war schon fertig
-bla2 bla2 \korrektur{beliebiger2 {} {Inhalt2 {mit2}} Klammern2} blub2 blub2
-bla3 bla3 \korrektur{beliebiger3 {} {Inhalt3 {mit3}} Klammern3} blub3 blub3
-bla4 bla4 \geloescht{\foo4{bar4}} \korrektur{beliebiger4 {} {Inhalt4 {mit4}} Klammern4} blub4 blub4
+bla2 bla2 <beliebiger2 {} {Inhalt2 {mit2}} Klammern2> blub2 blub2
+bla3 bla3 <beliebiger3 {} {Inhalt3 {mit3}} Klammern3> blub3 blub3
+bla4 bla4 \geloescht{\foo4{bar4}} <beliebiger4 {} {Inhalt4 {mit4}} Klammern4> blub4 blub4
bla5 bla5 \geloescht{\foo51{bar51}} uuups \geloescht{\foo52{bar52}} blub5 blub5
-bla6 bla6 \korrektur{\foo61{bar61}} uuups \korrektur{\foo62{bar62}} blub6 blub6
+bla6 bla6 <\foo61{bar61}> uuups <\foo62{bar62}> blub6 blub6
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7658
|
Interessanter Ansatz. sed hat glaube ich keine rekursiven Ausdrücke. Man könnte allerdings was mit Schleifen bzw. Sprungmarken basteln. | sed -r \
-e ':bump' -e 's/#(~*[AB])#/#~\1#/g' -e 't goto' \
-e ':goto' -e 's/\{([^{}]*)\}/#A#\1#B#/' -e 't bump' \
-e 's/\\korrektur#(~*)A#(.*)#\1B#/<\2>/' \
-e 's/#~*A#/{/g' -e 's/#~*B#/}/g'
|
Zeile 2: Platzhalter um ein ~ erweitern. (Anstelle des Zählers) Zeile 3: { } ohne weitere Klammern dazwischen durch Platzhalter ersetzen. Zeile 4: \korrektur{} mit zugehörigem Platzhalter (gleiche Anzahl ~~~) entfernen. (die < > dienen der Veranschaulichung). Zeile 5: Platzhalter mit beliebigen ~ wieder zu { } wandeln.
Um auch noch \geloescht{} zu entfernen, einfach die Zeile 4 duplizieren und entsprechend anpassen (\\geloescht und weg mit der \2 ).
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
frostschutz schrieb: Interessanter Ansatz. sed hat glaube ich keine rekursiven Ausdrücke.
Ich denke nicht. Ich kenne das nur von Perl und Ruby. Vermutlich gibt es noch andere Engines, die das ebenfalls beherrschen.
Zeile 2: Platzhalter um ein ~ erweitern. (Anstelle des Zählers) Zeile 3: { } ohne weitere Klammern dazwischen durch Platzhalter ersetzen. Zeile 4: \korrektur{} mit zugehörigem Platzhalter (gleiche Anzahl ~~~) entfernen. (die < > dienen der Veranschaulichung).
Das ist der entscheidende Trick: man zählt durch Wiederholung der Tilde und nutzt dann die Möglichkeit "niederer" Regex-Engines über eine Backreference die zugehörige öffnende Klammer zu finden. Cool! Das arbeitet schon fast wie eine Touringmaschine. 😉 Und ich habe wieder ein bisschen über sed gelernt (Sprungmarken und bedingte Sprünge). 👍 Danke! robert PS: Ich hatte oben noch die Anmerkung vergessen, dass "<" und ">" im Ersetzungsausdruck auch nur zur Verdeutlichung sind um die ersetzte Stelle hervorzuheben. Am Ende würde man die rauslassen und der Ausdruck für die Ersetzung wäre nur noch "\\1".
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7658
|
rklm schrieb: Und ich habe wieder ein bisschen über sed gelernt (Sprungmarken und bedingte Sprünge). 👍
Ich nutze die hier auch zum ersten Mal, per Google gefunden als ich nach sed und rekursiven Ausdrücken gesucht habe... Muss auch offen zugeben daß ich es noch nicht 100% verstehe. Rein theoretisch hätte ich gedacht, daß man das -e 't goto' weglassen könnte, weil das dann ja eh direkt danach kommt. Aber dann bleibt sed in einer Endlosschleife hängen. Das Problem mit den Platzhaltern ist natürlich daß die niemals so im Dokument vorkommen dürfen. Ob #A#/#B# da eindeutig genug ist... muss man ggf. anpassen.
|