bloginista
Massimiliano Siddi
Home
  • Blog

Regex: Zeichen beim Ersetzen umwandeln

19. Oktober 2008 23:28 von madmax

Unlängst hatte ich einige Grafikdateien, die den Underscore im Dateinamen enthielten. Da diese Zeichen in LaTeX zu Problemen führen, weil LaTeX solche Dateien nicht findet, wollte ich die Dateien einfach umbenennen. Dabei wollte ich das '_' löschen und den folgenden Buchstaben in einen Großbuchstaben umwandeln. Diesem Vorhaben zugute kam die Tatsache, dass der Underscore immer zwischen zwei Kleinbuchstaben vorkommt. Es sollte also durch einen sehr einfachen regulären Ausdruck möglich sein, den Dateinamen umzuwandeln.

Regex: Substitution einsetzen

Eine erste, einfache Lösung des Problems hat für jeden Buchstaben, der dem Underscore folgt, eine eigene Ersetzungsregel vorgesehen:

s/\_a/A/g
s/\_b/B/g
...

Das ist aber extrem unelegant und hässlich, da man viel tippen muss und damit die Fehleranfälligkeit steigt. Besser wäre es, wenn man die gesamte Klasse der Zeichen in einem Ausdruck zusammenfassen könnte und anschließend in der Ersetzungsregel schreibt, dass man die Großbuchstabenvariante des Buchstabens in die Ausgabe setzen möchte.

In regulären Ausdrücken lassen sich Funktionen jedoch nicht direkt aufrufen, sodass eine Lösung wie die folgende nicht so ohne Weiteres geht:

s/\_([a-z])/uc($1)/g

Das Ergebnis der obigen Funktion würde eine Zeichenkette wie "_a" mit "uc(a)" ersetzen, da die Funktion beim Ersetzen nicht ausgewertet wird. Stattdessen müsste man sich bei der Substitution einen Perl-Ausdruck als String zusammensetzen, in der uc() verkettet wird. Diesen Perl-Ausdruck müsste man anschließend durch den Aufruf von 'eval()' auswerten, damit das gewünschte Ergebnis zustande kommt.

In Perl gibt es allerdings eine sehr einfache und geniale Lösung für dieses Problem: Escape-Sequenzen. Funktionen wie uc() (= upper case) und lc() (= lower case) kann man über entsprechende Escape-Sequenzen ausführen, die man vor den umzuwandelnden String setzt:

s/\_([a-z])/\u$1/g

\u wandelt das Zeichen, das in der Back-Reference-Variablen $1 steckt, in einen Großbuchstaben um.

Perl sieht insgesamt folgende Escape-Sequenzen vor:

  • \u ersetzt das erste Zeichen eines Strings durch den entsprechenden Großbuchstaben.
  • \l ersetzt das erste Zeichen eines Strings durch den entsprechenden Kleinbuchstaben.
  • \U ersetzt alle Zeichen in einem String durch die entsprechenden Großbuchstaben.
  • \L ersetzt alle Zeichen in einem String durch die entsprechenden Kleinbuchstaben.

Und wie mache ich das in PHP?

Da diese Escape-Sequenzen auf Perl-interne Funktionen zurückgreifen, kann man sie leider nicht in PHP benutzen. Dafür sieht PHP allerdings zwei verschiedene Wege vor, wie man bei der Substitution Funktionen einsetzen kann:

  • Man setzt - ähnlich wie in Perl - eval() ein
  • Man benutzt Callback-Funktionen

Eval einsetzen

Wenn man in PHP Strings mit regulären Ausdrücken ersetzen will, kann man zu diesem Zweck die Funktion preg_replace einsetzen. Der Aufruf der Funktion sieht wie folgt aus:

$result = preg_replace('/\_a/', 'A', $fileName);

$fileName ist hier die String-Variable, die den Namen einer Datei enthält. Die Idee ist, alle Underscores im Dateinamen zu entfernen und stattdessen Camel Case zu benutzen.

Der erste String-Parameter enthält den regulären Ausdruck, der das zu ersetzende Muster beschreibt. Der zweite String-Parameter enthält den String, mit dem jeder Treffer des regulären Ausdrucks ersetzt werden soll. Der dritte Parameter enthält den String, auf den die Substitutionsoperation angewendet werden soll.

Man kann nun den zweiten Parameter durch einen Funktionsaufruf ersetzen, der anschließend durch PHP evaluiert werden soll. Dazu muss man jedoch den regulären Ausdruck im ersten Parameter durch den Modifier 'e' (für 'eval') erweitern. Anschließend kann man im zweiten Parameter die gewünschte String-Funktion aufrufen:

$result = preg_replace('/\_([a-z])/e', 'ucfirst('\\1')', $fileName);

Damit der Ausdruck im zweiten Parameter funktioniert, darf man nicht mit dem '$' arbeiten, um auf die Back-Reference-Variable zuzugreifen. Stattdessen muss man Backslash benutzen, der zudem durch ein weiteres Backslash maskiert werden muss.

Callback-Funktionen benutzen

Um eine Callback-Funktion zu benutzen, kann man die PHP-Funktion preg_replace_callback() einsetzen:

$result = preg_replace_callback('/\_([a-z])/', 'myCallbackFunction', $fileName);

Im obigen Beispiel ist der Parameter 'myCallbackFunction' der Name der Callback-Funktion.preg_replace_callback übergibt dieser Funktion ein Array mit allen Treffern des Suchmusters (erster Parameter). Die Callback-Funktion sollte für jeden Treffer eine Ersetzungszeichenkette liefern. Die Calback-Funktion könnte zum Beispiel so aussehen:

function myCallBackFunction($param) {
return strtoupper($param[0]);
}

Da das an die Callback-Funktion übergebene Array nur den geklammerten Ausdruck als Treffer enthält, kann man in diesem Fall einfach auf das erste Element des Arrays zugreifen. Im obigen Beispiel wird das erste Feld einfach an die Funktion strtoupper() übergeben, wobei das Ergebnis direkt an die aufrufende Funktion zurückgegeben wird.

Eine Übersicht der PCRE-Bibliothek in PHP könnt ihr im PHP-Handbuchkapitel zu PCRE finden.

Posted in Programing

Keine Kommentare


(Kommentarbereich geschlossen)

← Ältere Einträge Neuere Einträge →