Alles über die Verwendung von regulären Ausdrücken in Calibre

Reguläre Ausdrücke werden an vielen Stellen in calibre verwendet, um den Inhalt und die Metadaten von E-Büchern auf raffinierte Weise zu manipulieren. Dieses Tutorial ist eine vorsichtige Einführung, mit der man den Umgang mit regulären Ausdrücken erlernen kann.

Vorweg ein Wort der Warnung - und der Ermutigung

Nun wird es unvermeidbar ein wenig technisch - immerhin sind reguläre Ausdrücke ein technisches Werkzeug, mit dem man technisches Zeug erledigt. Ich werde den einen oder anderen Fachbegriff verwenden und Gedankengänge, die kompliziert oder auch verwickelt wirken mögen. Ich werde versuchen, diese Gedanken so gut ich kann zu erklären, aber ich werde nicht ohne sie auskommen. Nur sollten Sie sich von diesem Fachchinesisch nicht abschrecken lassen, denn ich habe versucht, alle neuen Begriffe zu erklären. Und obwohl reguläre Ausdrücke an sich wie mysteriöse, schwarze Magie wirken (oder, nüchterner gesagt, wie ein Durcheinander irgendwelcher Buchstaben, Zahlen und Zeichen), verspreche ich hiermit, dass sie gar nicht so kompliziert sind. Selbst diejenigen, die reguläre Ausdrücke wirklich gut verstehen, haben schon mal Probleme, die komplexeren zu durchschauen, aber sie aufzuschreiben ist gar nicht so schwer - Sie bauen den Ausdruck schrittweise zusammen. Also: Treten Sie vor und folgen Sie mir in den Kaninchenbau!

Wo in calibre sind reguläre Ausdrücke verwendbar?

Es gibt nur wenige Stellen, an denen Calibre Reguläre Ausdrücke verwendet. Da wären, die Search & replace in den Konvertierungsoptionen, Metadatenerkennung auf Grund von Dateinamen in the Importeinstellungen und Suchen & Ersetzen beim massenhaften Bearbeiten der Metadaten von Büchern. Der Calibre-Bucheditor kann ebenfalls Reguläre Ausdrücke in seiner Search and replace-Funktion verwenden. Schließlich kannst du Reguläre Ausdrücke auch beim Suchen in der Calibre-Buchliste und innerhalb des Calibre-E-Book-Betrachters verwenden.

Was um Himmels Willen ist ein „regulärer Ausdruck“?

Reguläre Ausdrücke beschreiben Mengen von Zeichen oder Zeichenfolgen. Ein einzelner regulärer Ausdruck entspricht unter Umständen einer ganzen Reihe verschiedener Zeichenfolgen. Und das macht reguläre Ausdrücke so mächtig: Sie beschreiben kurz und knapp eine möglicherweise große Zahl von Varianten.

Bemerkung

Dabei benutze ich den Begriff Zeichenfolge so wie in einer Programmiersprache, nämlich eine Folge von einem oder mehreren Zeichen, wobei als Zeichen die eigentlichen Buchstaben und Zahlen, aber auch Satzzeichen und sogenannten Leerraum (Umbrüche, Tabulatorschritte usw.) gelten. Man beachte, dass meistens Klein- und Großbuchstaben nicht als gleichwertig angesehen werden. Es ist also nicht egal, ob man „a“ oder „A“ schreibt. In der Suchleiste von calibre spielt die Groß- oder Kleinschreibung keine Rolle, wohl aber bei den Einstellungen für die Konvertierung. Es gibt zwar eine Möglichkeit, alle regulären Ausdrücke unabhängig von Klein- und Großbuchstaben zu machen, aber dazu kommen wir später. Es wird kompliziert, weil reguläre Ausdrücke Abweichungen in den Zeichenfolgen zulassen, denen sie entsprechen. Anders gesagt: Ein einziger passt zu verschiedenen Zeichenfolgen - deshalb werden reguläre Ausdrücke ja überhaupt verwendet. Mehr dazu in Kürze.

Bitte etwas genauer!

Klar, darum machen wir das ja! Der wichtigste Gedanke bei regulären Ausdrücken zuerst: Eine Zeichenfolge an sich ist ein regulärer Ausdruck, der sich selbst entspricht. Wenn ich also einen regulären Ausdruck für die Zeichenfolge \"Hallo, Welt!" suche, kann ich einfach "Hallo, Welt!" benutzen. Ja, es wirklich so simpel! Sie sollten beachten, dass dies nur für die exakte Zeichenfolge "Hallo, Welt!" gilt, nicht etwa für "Hallo, wElt!" oder "hallo, welt!" oder ähnliche Zeichenfolgen.

Das hört sich nicht schlecht an. Was kommt als Nächstes?

Als Nächstes kommen jetzt die richtig guten Sachen. Sie erinnern sich daran, dass reguläre Ausdrücke zu verschiedenen Zeichenfolgen passen können? Da wird es nun etwas komplizierter. Mal angenommen, als praktisches Beispiel, Sie wollen ein Buch konvertieren mit einer ganz hässlichen Zeilenangabe in der Fußzeile, so etwas wie „Seite 5 von 423“. Offensichtlich steigt die Seitenzahl von 1 bis 423, und Sie bräuchten 423 verschiedene Zeichenfolgen, oder? Falsch: Tatsächlich können Sie mit regulären Ausdrücken Zeichenmengen festlegen, die zueinander passen. Zur Festlegung einer solchen Menge schreiben Sie alle betreffenden Zeichen in eckige Klammern. Zum Beispiel entspricht die Menge [abc] entweder dem Zeichen „a“, „b“ oder „c“. Mengen entsprechen immer nur einem der Zeichen dieser Menge. Sie „verstehen“ übrigens auch Zeichen-Bereiche, so dass Sie für alle Kleinbuchstaben (ohne Umlaute) die Menge [a-z] und für sämtliche Klein- und Großbuchstaben (wieder ohne Umlaute) die Menge [a-zA-Z] schreiben können - und so weiter. Soweit klar? Mit dem regulären Ausdruck Seite [0-9] von 423 hätten Sie also etwas Passendes für die ersten neun Seiten und benötigten nun nur noch drei Ausdrücke: Seite [0-9][0-9] von 423 wäre der zweite Ausdruck, entsprechend den zweistelligen Seitenzahlen, und den dritten Ausdruck können Sie sicherlich selbst finden. Ja, versuchen Sie es und schreiben Sie ihn auf!

Hey, toll! Langsam bekommt alles einen Sinn!

Oh, ich hatte gehofft, dass Sie das sagen. Aber seien Sie bereit, jetzt wird es noch besser! Bisher haben wir gesehen, dass Mengen einem von mehreren Zeichen entsprechen. Aber man kann ein Zeichen oder eine Menge sogar wiederholen, und dadurch brauchen wir für das Beispiel mit den Seitenzahlen nur noch einen Ausdruck. Genau, EINEN! Aufregend, was? Ist es wirklich! Es funktioniert so: Einige sogenannte Sonderzeichen, nämlich „+“, „?“ und „*“, wiederholen das Einzelelement direkt davor. (Element bedeutet hier entweder ein einzelnes Zeichen, eine Zeichenmenge, eine „Escape-Sequenz“, eine „Gruppe“ - mehr dazu später - oder kurz: jede beliebige Einheit eines regulären Ausdrucks.) Diese Zeichen werden als „Wildcards“, also als Joker, oder auch als Quantifizierer bezeichnet. Genauer gesagt, bedeutet das Fragezeichen „?“ 0 oder 1 Mal das vorherige Element, der Stern „*“ 0 oder mehrere Male das vorherige Element und das Pluszeichen „“+“ bedeutet 1 oder mehrere Male das vorherige Element. Ein paar Beispiele: Der Ausdruck a? würde „“ (also der leeren Zeichenfolge, was hier nicht gerade brauchbar wäre) oder „a“ entsprechen. Der Ausdruck a* würde „“, „a“, „aa“ oder noch mehr aufeinanderfolgenden a’s entsprechen. Und a+ entspricht „a“, „aa“ oder noch mehr aufeinanderfolgenden a’s - aber eben nicht der leeren Zeichenfolge! Dasselbe gilt für Mengen: Der Ausdruck [0-9]+ entspricht jeder natürlichen Zahl, egal welcher Länge! Jetzt weiß ich, was Sie denken: Wäre das nicht genau richtig für das Beispiel oben mit den Seitenzahlen? Ja, da haben Sie Recht: Der Ausdruck Seite [0-9]+ von 423 ganz für sich alleine würde allen Seitenangaben in diesem Buch entsprechen!

Bemerkung

Einen Hinweis zu diesen Jokern hätte ich aber: Sie haben die unschöne Angewohnheit, grundsätzlich so viel Text wie möglich entsprechen zu wollen. Seien Sie also vorsichtig im Umgang mit ihnen. Man bezeichnet dieses Verhalten auch als gierig oder gefräßig - Sie verstehen sicher, warum. Probleme machen zum Beispiel Markierungszeichen („Tags“), wie in der Zeichenfolge "<p class="calibre2">Titel fehlt hier</p>". Sagen wir, Sie möchten nach dem öffnenden „Tag“ (zwischen den ersten beiden spitzen Klammern - mehr zu „Tags“ später) suchen und halten den Ausdruck <p.*> für passend. Tatsächlich aber entspricht Ihr Ausdruck aber schon der gesamten Zeichenfolge! (Ach so: Das Zeichen „.“ ist auch ein Sonderzeichen. Es entspricht praktisch allem außer einem Zeilenumbruch, so daß grundsätzlich der Ausdruck .* auf jede vorstellbare Textzeile passt.) Benutzen Sie also stattdessen <p.*?>, wodurch der Joker "*" seine Gefräßigkeit verliert. Dieser Ausdruck erfasst wirklich nur den ersten, öffnenden „Tag“, wie geplant. Genau genommen, gibt es noch eine andere Möglichkeit: Der Ausdruck <p[^>]*> würde ebenfalls nur dem öffnenden „Tag“ entsprechen. Eine Begründung folgt später. Hier nur so viel: Recht häufig gibt es mehr als eine Art, einen regulären Ausdruck z formulieren.

Tja, das mit den Sonderzeichen ist ja gut und schön. Aber wie kann ich nach einem Punkt oder einem Fragezeichen suchen?

Natürlich geht auch so etwas: Sie brauchen nur einen „Backslash“ vor ein Sonderzeichen zu setzen, und es wird als das Zeichen selbst verstanden, ohne irgendeine Sonderbedeutung. Eine solche Kombination aus einem „Backslash“ mit einem einzelnen Zeichen nennt man Escape-Sequenz, und unter „Escaping“ versteht man, vor ein Sonderzeichen einen „Backslash“ zu schreiben. Solche Escape-Sequenzen gelten als einzelne Elemente. Es gibt auch Escape-Sequenzen, die nicht nur Sonderzeichen betreffen; zum Beispiel ist "\t" die Sequenz für einen Tabulatorschritt. Wir kommen später noch zu ähnlichen Escape-Sequenzen. Was die Sonderzeichen betrifft, sollten Sie einfach mal folgendes annehmen: Jedes Zeichen in dieser Einführung, das eine besondere Funktion hat, gilt als Sonderzeichen und benötigt den „Backslash“, wenn man das Zeichen selbst meint.

So, und welche Mengen sind nun am brauchbarsten?

Knew you’d ask. Some useful sets are [0-9] matching a single number, [a-z] matching a single lowercase letter, [A-Z] matching a single uppercase letter, [a-zA-Z] matching a single letter and [a-zA-Z0-9] matching a single letter or number. You can also use an escape sequence as shorthand:

\d

is equivalent to [0-9]

\w

is equivalent to [a-zA-Z0-9_]

\s

is equivalent to any whitespace

Bemerkung

„Whitespace“ is a term for anything that won’t be printed. These characters include space, tabulator, line feed, form feed, carriage return, non-breaking spaces, etc.

Ein letzter Hinweis zu Mengen: Sie können eine Menge auch so festlegen, dass jedes Zeichen gemeint ist außer denen in der Menge! Dazu schreiben Sie als allererstes Zeichen ein "^" in die Menge. So entspricht [^a] jedem Zeichen außer dem „a“. Man spricht auch vom Komplement dieser Menge. Die Abkürzungen mit Hilfe von Escape-Sequenzen funktionieren auch mit Komplementbildung: "\D" bedeutet so viel wie „alles außer Zahlen“, anders ausgedrückt also [^0-9]. Der oben erwähnte Ausdruck <p[^>]*> versucht, wie man sieht, jedem Zeichen zu entsprechen mit Ausnahme der schließenden spitzen Klammer.

Aber wenn ich jetzt nach ein paar unterschiedlichen Zeichenfolgen gleichzeitig suchen möchte - wird die Sache dann sehr kompliziert?

Keine Angst, das Leben ist noch immer schön und leicht. Betrachten Sie dieses Beispiel: Das Buch, das Sie konvertieren hat „Titel“ auf jeder ungeraden, und „Autor“ auf jeder geraden Seite stehen. Das sieht im Druck toll aus, stimmt’s? Nur: Bei Ebooks ist das lästig. Sie können ganze Ausdrücke mit normalen Klammern gruppieren, und das Zeichen "|" erlaubt Ihnen entweder den Ausdruck links oder denjenigen rechts davon zu finden. Kombinieren Sie diese beiden und sie haben es. Das war zu schnell? OK, als Erstes kombinieren wir die Ausdrücke für gerade und ungerade Seiten, erhalten also (Title)(Author) für unsere zwei benötigten Ausdrücke. Nun vereinfachen wir das Ganze, indem wir den senkrechten Strich verwenden ("|" wird senkrechter Strich oder Verkettungszeichen genannt): Wenn Sie den Ausdruck (Title|Author) verwenden finden Sie entweder „Titel“ (auf den ungeraden Seiten) oder „Autor“ (auf den geraden Seiten). Na, war das nicht einfach?

Sie können den senkrechten Strich natürlich auch ohne gruppierende Klammern verwenden. Erinnern Sie sich, dass ich sagte Quantifizierer wiederholten das vorangegangene Element? Nun, der senkrechte Strich funktioniert ein wenig anders: Der Ausdruck „Titel|Autor“ wird also entweder die Zeichenfolge „Titel“ oder die Zeichenfolge „Autor“ finden, genau wie das vorhergehende Beispiel mit der Gruppierung. Der senkrechte Strich wählt aus zwischen der ganzen Zeichenfolge vor und der nach ihm. Wollten Sie also die Zeichenfolgen „Calibre“ und „calibre“ finden und dabei nur zwischen dem großen und dem kleinen „c“ wählen, müssten Sie den Ausdruck (c|C)alibre verwenden, bei dem die Gruppierung sicherstellt, dass nur das „c“ gewählt wird. Sollten Sie c|Calibre verwenden, fänden Sie die Zeichenfolgen „c“ oder „Calibre“, was nicht unsere Absicht war. Kurz gesagt: Verwenden Sie im Zweifel die Gruppierung zusammen mit dem senkrechten Strich.

Da fehlt noch …

… es gäbe da noch eine letzte, wirklich geschickte Sache, die Sie mit Gruppen anstellen können. Wenn Sie einen Gruppierungsausdruck haben, den Sie zuvor eingesetzt haben, können Sie Referenzen auf diese Gruppe im weiteren Ausdruck verwenden: Gruppen werden beginnend mit 1 nummeriert, und Sie werden referenziert, indem die Nummer der Gruppe mit einer „Escape-Sequenz“ versehen wird, folglich würde die fünfte Gruppe als \5 referenziert. Daher fänden Sie bei einer Suche nach ([^ ]+) \1 in der Zeichenfolge „Test Test“ die komplette Zeichenfolge!

Hatten Sie anfangs nicht gesagt, dass reguläre Ausdrücke auch unabhängig von Groß- und Kleinschreibung gemacht werden könnten?

Ja, das habe ich. Danke für’s Aufpassen. Sie können Calibre sagen, wie es mit bestimmten Dingen umgehen soll, indem Sie sogenannte „Flags“ verwenden. Sie fügen Flags in ihren Ausdruck mithilfe des speziellen Konstrukts (?Flag hierher) ein, in welchem Sie selbstverständlich „Flags hierher“ durch die genauen Flags, die Sie wollen, ersetzen würden. Um die Groß-/Kleinschreibung zu ignorieren lautet die Flag i, folglich würden Sie (?i) in Ihren Ausdruck einfügen. Also würde (?i)test mit „Test“, „tEst“, „TEst“ übereinstimmen und jegliche Variation der Groß-/Kleinschreibung, die Ihnen einfällt.

Das Flag s sorgt dafür, dass mit dem Punkt jedes beliebige Zeichen gefunden wird, einschließlich „Newline“. Wenn du mehrere Flags in einem Ausdruck verwenden möchtest, fasse sie einfach in der selben Anweisung zusammen: (?is) würde Groß-/Kleinschreibung ignorieren und der Punkt würde alle Zeichen finden. Es spielt keine Rolle, welches Flag du zuerst angibst: (?si) würde das selbe bewirken wie die Kombination oben.

Mir scheint, ich verstehe allmählich etwas von regulären Ausdrücken … und wie benutze ich sie nun in calibre?

Konvertierungen

Lass uns mit den Umwandlungseinstellungen beginnen. Im Teil Search & replace kannst du eine Regexp (kurz für Regular expression) eingeben, der die Zeichenkette beschreibt, die während der Umwandlung ersetzt wird. Der angenehme Teil ist der Assistent. Klicke auf den Zauberstab und du erhälst eine Vorschau dessen, was Calibre während des Umwandlungprozesses „sieht“. Scrolle zu der Zeichenkette, die du entfernen möchtest, wähle sie aus, kopiere sie und füge sie in das Regexp-Feld oben im Fenster ein. Wenn es variable Teile gibt, wie Seitenzahlen oder ähnliches, verwende Mengen und Quantifizierer um diese abzudecken und wenn du schon mal dabei bist: Denke daran Sonderzeichen zu maskieren, falls es welche gibt. Drücke auf die Schaltfläche Test und Calibre hebt die Teile hervor, die ersetzt würden, wenn du diesen Regexp anwendest. Sobald du zufrieden bist, drücke OK und starte den Prozess. Sei vorsichtig careful wenn deine Quelle mit Tags wie in diesem Beispiel versehen ist:

Maybe, but the cops feel like you do, Anita. What's one more dead vampire?
New laws don't change that. </p>
<p class="calibre4"> <b class="calibre2">Generated by ABC Amber LIT Conv
<a href="http://www.processtext.com/abclit.html" class="calibre3">erter,
http://www.processtext.com/abclit.html</a></b></p>
<p class="calibre4"> It had only been two years since Addison v. Clark.
The court case gave us a revised version of what life was

(Schamlos stibitzt aus dieser Forumsdiskussion). Sie müssten auch einige der Marken („Tags“) entfernen. In diesem Beispiel würde ich empfehlen, mit der Marke <b class="calibre2"> anzufangen, die Sie dann mit der entsprechenden schließenden Marke beenden müssen, die in diesem Fall einfach das nächste <\b> ist. (Öffnende Marken lauten <Marke>, schließende Marken </Marke>; wenden Sie sich an ein gutes HTML-Handbuch oder fragen Sie im Forum nach, falls Ihnen dieser Punkt nicht ganz klar ist.) Die öffnende Marke kann hier mit <b.*?>, die schließende mit </b> beschrieben werden, also könnten wir alles zwischen diesen Marken mit <b.*?>.*?</b> entfernen. Diesen Ausdruck zu verwenden wäre aber keine gute Idee, denn es würde alles von <b>-Marken eingeschlossene (diese geben übrigens Text in Fettdruck wieder) entfernen und dabei jede Wette Teile des Buches löschen. Stattdessen fügen Sie auch den Anfang der eingeschlossenen Zeichenfolge ein, was den regulären Ausdruck zu <b.*?>\s*Generated\s+by\s+ABC\s+Amber\s+LIT.*?</b> macht. Hier wurden die \s mit Quantifizierern eingefügt, statt die Leerzeichen selbst wie in der Zeichenfolge einzusetzen, um jegliche vorkommenden Variationen derselben abzufangen. Vergessen Sie beim Ausprobieren eines neuen Ausdruckes nicht zu überprüfen, was Calibre entfernen würde, um sicherzugehen, dass Sie keine Abschnitte verlieren, die Sie behalten wollten. Wenn Sie nur ein Auftreten überprüfen, übersehen Sie vielleicht ein fälschlicherweise gefundenes woanders im Text. Beachten Sie außerdem: Sollten Sie aus Versehen mehr oder weniger Marken als sie wollten entfernt haben, versucht Calibre, den beschädigten Code nach der Entfernung zu reparieren.

Hinzufügen von Büchern

Etwas anderes, wofür Sie reguläre Ausdrücke verwenden können, ist das Extrahieren von Metadaten aus Dateinamen. Sie finden diese Funktion im Bereich „Bücher hinzufügen“ der Einstellungen.Es gibt hierbei eine Spezialfunktion: Sie können Feldnamen für die Metadaten-Felder vewenden, beispielsweise bedeutete (?P<title>), dass Calibre diesen Teil der Zeichenfolge als Buchtitel einsetzen würde. Die erlaubten Feldnamen sind in den Fenstern aufgelistet, zusammen mit einem weiteren netten Testfeld. Ein Beispiel: Nehmen wir an, Sie wollen einen ganzen Haufen Dateien importieren, die ähnlich wie Klassische Texte: Die göttliche Komödie von Dante Alighieri.mobi benannt sind. (Selbstverständlich befindet sich das schon in Ihrer Bibliothek, denn wir alle lieben klassische italienische Dichtkunst.) … oder Monumentalwerke der Science-Fiction: Die Foundation-Trilogie von Isaac Asimov.epub. Dies ist offensichtlich ein Namensschema, aus dem Calibre keinerlei sinnvolle Informationen extrahieren wird – sein Standardausdruck für die Extraktion von Metadaten ist (?P<title>.+) - (?P<author>[^_]+). Ein regulärer Ausdruck, der hier funktionieren würde, wäre [a-zA-Z]+: (?P<title>.+) von (?P<author>.+). Beachten Sie bitte, dass Sie in der Gruppe für das jeweilige Metadaten-Feld Ausdrücke einsetzen müssen, um zu beschreiben was eigentlich auf das Feld passt. Und beachten Sie außerdem, dass Sie beim verwenden von Calibres vorgegebenem Testfeld die Dateiendung zu ihrem Versuchs-Dateinamen hinzufügen müssen, andernfalls werden Sie trotz eines korrekten Ausdrucks nichts finden.

Gleichzeitiges Bearbeiten von Metadaten

The last part is regular expression Search and replace in metadata fields. You can access this by selecting multiple books in the library and using bulk metadata edit. Be very careful when using this last feature, as it can do Very Bad Things to your library! Doublecheck that your expressions do what you want them to using the test fields, and only mark the books you really want to change! In the regular expression search mode, you can search in one field, replace the text with something and even write the result into another field. A practical example: Say your library contained the books of Frank Herbert’s Dune series, named after the fashion Dune 1 - Dune, Dune 2 - Dune Messiah and so on. Now you want to get Dune into the series field. You can do that by searching for (.*?) \d+ - .* in the title field and replacing it with \1 in the series field. See what I did there? That’s a reference to the first group you’re replacing the series field with. Now that you have the series all set, you only need to do another search for .*? - in the title field and replace it with "" (an empty string), again in the title field, and your metadata is all neat and tidy. Isn’t that great? By the way, instead of replacing the entire field, you can also append or prepend to the field, so, if you wanted the book title to be prepended with series info, you could do that as well. As you by now have undoubtedly noticed, there’s a checkbox labeled Case sensitive, so you won’t have to use flags to select behaviour here.

Well, that just about concludes the very short introduction to regular expressions. Hopefully I’ll have shown you enough to at least get you started and to enable you to continue learning by yourself- a good starting point would be the Python documentation for regexps.

Noch eine letzte Warnung: Reguläre Ausdrücke sind mächtig, können aber wirklich leicht Unheil anrichten. Darum gibt es calibre hervorragende Möglichkeiten festzustellen, ob Ihre regulären Ausdrücke genau das tun, was sie sollen. Nutzen Sie das aus! Versuchen Sie nicht, sich selbst ein Bein zu stellen. (Hach, diesen Ausdruck liebe ich …) Wenn Sie aber trotz dieser Warnung über Ihre Beine (oder andere Körperteile) stolpern, dann nehmen Sie es als eine Lehre.

Danksagung

Ich bedanke mich für Hinweise, Korrekturen und so weiter bei:

  • ldolse

  • kovidgoyal

  • chaley

  • dwanthny

  • kacir

  • Starson17

  • Orpheu

For more about regexps see The Python User Manual. The actual regular expression library used by calibre is: regex which supports several useful enhancements over the Python standard library one.