Mittwoch, 17. Dezember 2014

Perl RegEx mit variable length look-behind um Römische Zahlen in Text bedingt zu ersetzen

HerrenbergStiftskirche060427
Quelle: Wikimedia, Lizenznachweis sh. Link Bild

Das Problem


In einem Text sollen Römische Zahlen durch die selbstdefinierte Asciidoc-Notation roman::number[] ausgezeichnet werden. Asciidoc erlaubt zur Zeit allerdings nicht weitere Markups innerhalb einer Bildauszeichnung.

Sprich:

.Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.]

funktioniert, aber
.Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.]

nicht, da in Asciidoc Tags der Form image:foo.png[baz] innerhalb von baz keine anderen asciidoc-Tags enthalten darf.

Römische Zahlen finden


Wenn wir nach römischen Zahlen suchen, könnten wir Reguläre Ausdrücke (RegEx) benutzen. In Perl sähe eine RegEx dann beispielsweise so aus:

my $roman_number = qr{
(
    (I{1,3})|  # I … III
    (I?V)|     # IV … V
    (VI{1,3})| # VI … VIII
    (I?X)      # IX … X
)
}x;


Teststring


Bevor wir weitermachen, sollten wir uns einen Teststring definieren, der alle möglichen Varianten enthält und es uns erlaubt die RegExes zu überprüfen:

my $string=<<TEST;
.Konrad I. von
.Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.
break::folding[test] .Konrad I. von Wettin. break::folding[test2] Luitgard, Konrads I. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.]
Im Frühjahr
fertig. Im Frühjahr
mahlin. Im Frühling 1147 nahm er mit vielen der ſächſiſchen Fürſten das
als der Imker
I. Foo
Foo I.
Foo II.
Foo III.
Foo IV.
Foo V.
Foo VII.
Foo VIII.
Foo IX.
Foo X.
Foo XIII.
Foo XIV.
Foo XX.
Foo XV.
BarI.
BarII.
IBaz
Vettel
Xanthippe
Baz IIII.
Baz IIV.
Baz IIIV.
Baz IIX.
Baz XIIII
Baz VV.
Baz VX.
Baz IXIX.
Baz IVX.
Baz IIX.
Baz VIIX.
Baz XIVI.
TEST

Lookbehind und Lookahead


Unsere oben definierte RegEx allein reicht für obiges Beispiel nicht, da wir zB. nicht innerhalb einer []-Klammer römische Zahlen ersetzen wollen. Eine Abhilfe wäre, wenn wir im String beliebig zurückschauen könnten, ob eine Klammer noch offen ist.

In Perl sind zwar beliebig tiefe lookahead-Bedingungen in Regulären Ausdrücken erlaubt, allerdings nicht in lookbehind-Bedingungen.

Sprich, mit (?<=foo)bar würden wir auf bar matchen, wenn vorher der fixe String foo auftaucht. Aber (?<=fo+)bar funktioniert unter Perl5 nicht.

Lookahead hat diese Einschränkungen nicht, wenn ich also auf foo matchen will, aber nur, wenn bar oder baar oder ba…ar folgen, dann kann ich foo(?=ba+r) schreiben.

variable length lookbehind über variable length look ahead


Über einen Post in einem Forum bin ich auf eine Lösung gestolpert: Drehe den String und die RegEx um. Statt:

"foobar" =~ s/(?<=fo+)bar/baz/; #funktioniert nicht in Perl5

also alles umdrehen zu:

"raboof" =~s/rab(?=o+f)/zab/; # zaboof -> reverse zaboof = foobaz

Die Lösung


Zurück zum Problem mit Asciidoc und römischen Zahlen, die Lösung sieht in Gänze nun wie folgt aus:

my $rstring = reverse $string;
my $roman_revregex=qr{
    (?<![IVXa-zſßäöü])(          #lookbehind
    (I{1,3})|            # I ... III
    (I{1,3}V)|           # VI ... VIII
    (VI{0,1})|           # IV ... V
    (XI{0,1})|           # IX .. X
    (I{1,3}X)|           # XI .. XIII
    (VI{0,1}X)|          # XIV ... XV
    (I{1,3}VX)|          # XVI ... XVIII
    (XX)                # XX
    )(?=\ )(?![^\[\]]*\[) # lookahead
    }x;
$rstring=~s#$roman_revregex#\]$1\[rebmun::namor#g;
$string = reverse $rstring;
print $string, "\n\n";

Dies ergibt dann folgenden String:

.Konrad roman::number[I]. von
.Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.
break::folding[test] .Konrad roman::number[I]. von Wettin. break::folding[test2] Luitgard, Konrads roman::number[I]. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.]
Im Frühjahr
fertig. Im Frühjahr
mahlin. Im Frühling 1147 nahm er mit vielen der ſächſiſchen Fürſten das
als der Imker
I. Foo
Foo roman::number[I].
Foo roman::number[II].
Foo roman::number[III].
Foo roman::number[IV].
Foo roman::number[V].
Foo roman::number[VII].
Foo roman::number[VIII].
Foo roman::number[IX].
Foo roman::number[X].
Foo roman::number[XIII].
Foo roman::number[XIV].
Foo roman::number[XX].
Foo roman::number[XV].
BarI.
BarII.
IBaz
Vettel
Xanthippe
Baz IIII.
Baz IIV.
Baz IIIV.
Baz IIX.
Baz XIIII
Baz VV.
Baz VX.
Baz IXIX.
Baz IVX.
Baz IIX.
Baz VIIX.
Baz XIVI.

Dienstag, 9. Dezember 2014

Seitenfehler im Ebookreader PRS300 von Sony

Lange hatte ich mich gewundert. In meinem Projekt ›Bunte Bilder aus dem Sachſenlande« hatte ich etliche Mühen auf mich genommen, um möglichst exzellente Grafiken aus der Originalvorlage zu erzeugen und diese als SVG bereitzustellen, damit die Ebookreader diese Vektorgrafiken auf ihre bevorzugte Auflösung rendern können.

Das Programm epubcheck meldete keinerlei Fehler mehr und auf den diversen Ebookreadern auf meinem PC wurde das Epub2 soweit korrekt angezeigt.

Nur einzig und allein auf meinem Sony PRS300 hatte ich ein komisches Verhalten. Das Inhaltsverzeichnis wurde geladen und angezeigt. Doch sobald ich auf eine Seite ging, kam das Symbol "Seitenfehler". Wenn ich zwischendurch auf ein anderes Buch ging und später auf die Seite zurück, war manchmal der Seitenfehler verschwunden und die Seite korrekt gerendert. Nur beim Zurückkehren auf das Inhaltsverzeichnis, beim Vor- oder Zurückblättern  tauchte der Fehler wieder auf.

In einem letzten Test erzeugte ich ein Ebook, welches statt SVGs Bilder im PNG-Format abspeicherte. Und siehe da, das Ebook ließ sich nutzen.

Auf alle Fälle wäre ich jedem dankbar, der das Verhalten mit seinem Ebookreader mal versucht nachzustellen oder mir vielleicht eine Übersicht über die Einschränkungen der verschiedenen erhältlichen Ebookreader nennen kann. Über entsprechende Hinweise wäre ich sehr dankbar.

Dienstag, 2. Dezember 2014

Sachertorte

Es ist Weihnachtszeit und da der letzte Beitrag etwas her ist, gibt es heute ein Rezept aus „Schicht's Kochbuch – ausgewählte Rezepte“
Das Buch ist eigentlich eines von drei Heftchen, hier aus dem 1. Band, Mehlspeisen, im Druck von A. Haase, Prag. Die DNB verzeichnet als Erscheinungsjahr 1928-1931 (http://d-nb.info/56088897X).


Charakteristisch ist die minimalistische Darstellung der Rezepte.Hier das Rezept für Sachertorte aus Seite 38b:



Das Rezept in maschinenlesbarer Form:

Sacher-Torte.

Zutaten: 16 dkg Visan, 15 dkg Zucker, 8 dkg Kakao, 6 Eier, 15 dkg
Mehl, Sacherbuttercreme (siehe Creme), Schokoladenfondant (siehe Fondant).

Zub ereitung; DasVisan wird mit dem Zucker schaumig gemischt,
die Eidotter nach und nach dazugegeben, dann den Kakao daruntergemischt.

*Dazu kommt der Schnee von den Eiklar und zuletzt das Mehl. Bei mäßiger '

Hitze backen; nach dem Auskühlen in zwei Blätter schneiden und, mit Sacher-
buttercreme füllen, mit Schokoladenfondant überziehen und auf jedes Torten-
stück eine Praline aufsetzen. w ’

W o r a uf k o m mt e s a n? Die Torte vor dem Füllen einen Tag stehen
lassen. '

Was kann mißlingen? Die Masse läuft aus der Form, wenn sie
nicht genau in Papier eingeschlagen wird.
Die Sacher-Buttercreme wird auf S. 31 beschrieben:


Das Rezept in maschinenlesbarer Form:

 Sacherbuttercreme.

Z u t a t e n: 12 1/2 dkg Visan, 12 1/2 dkg Zucker, 2 Eigelb, 10 dkg Tunkmasse.
Z u b e r e i t u n g: Das Eigelb wird schaumig geschlagen, der Zucker wird
zum schwachen Flug gekocht und in einem schwachen Strahl in die flaumige Eigelbmasse hineingezogen; das Ganze dann kalt geschlagen. Nachher rührt
man es in das Visan, welches unterdessen schaumig gerührt wurde. Nun mischt man noch die aufgelöste Tunkmasse darunter.
W o r a u f  k o m m t e s a n? Das Eigelb gut aufschlagen.
Was kann m iß l in gen? Die Tunkmasse wird bröslig, wenn sie zu
warm aufgeweicht wird.
Das Ergebnis entstammt (ohne weitere Korrektur) der OCR mit dem folgenden Aufruf von Tesseract 3.03:
$> tesseract Schichts_Kochbuch_Bd1_38b.png Schichts_Kochbuch_Bd1_38b -l deu