Hey, Scripting Guy!Reguläre Ausdrücke

Die Scripting Guys von Microsoft

Laden Sie den Code für diesen Artikel herunter: HeyScriptingGuy2008_05.exe (150KB)

Im November 2007 hatten die Scripting Guys die Gelegenheit, auf ihrer Reise zur IT-Konferenz Tech•Ed in Barcelona einen Tag in Paris zu verbringen. Während der eintägigen Ruhepause nutzten wir die Möglichkeit, den Louvre, das weltberühmte Museum dieser Stadt, zu besuchen.

Wie fanden die Scripting Guys den Louvre? Die Antwort ist ganz einfach: Wir gingen bis zur Kathedrale Notre Dame und sind dann links abgebogen.

Ach so, Sie meinen, ob uns der Louvre gefallen hat? Größtenteils ja. Unser einziges Problem damit war, dass der Louvre, so wie viele Museen, zum Ansehen aber nicht zum Anfassen einlädt. Jeder weiß, dass die Mona Lisa viel besser aussehen würde, wenn sie Augenbrauen hätte. Doch aus unerfindlichen Gründen regt sich der Kurator des Louvre sehr auf, wenn man versucht, Verbesserungen an einem der Gemälde vorzunehmen.

Hinweis: Die Mona Lisa hat beiden Scripting Guys gut gefallen. Das war sogar eine angenehme Überraschung, denn nach all dem Rummel und den großen Erwartungen hatten wir befürchtet, dass es sich doch nur um ein weiteres unspektakuläres Gemälde handeln könnte. So war es aber nicht. Es war toll. (Obwohl die Augenbrauen fehlen.) Interessanterweise waren wir beide von der gleichermaßen hochgejubelten Venus von Milo enttäuscht. Keiner von uns beiden war beeindruckt. Der Scripting Guy, der diesen Artikel schreibt, sah in der Venus von Milo eigentlich keinen Sinn. Die Statue einer Frau, die keine Arme hat? Wie soll sie denn dann putzen oder spülen!?

Hinweis für unsere Leserinnen (falls wir noch welche haben): Das war offensichtlich ein Tippfehler. Wir meinten: Die Statue einer Frau, die keine Arme hat? Dabei kann sie zweimal so viel Arbeit verrichten wie ein Mann und auch noch richtig.

Die Scripting Guys entschuldigen sich für jegliche Missverständnisse aufgrund unserer ursprünglichen Aussage.

Wie auch immer, in dem Augenblick, in dem wir die großartigen Schätze des Louvre erblickten, wurden die beiden Scripting Guys vom selben Gedanken befallen: Wo sind die Toiletten? Während dieser Suche hatte der Autor einen weiteren Gedanken: Die Scripting Guys sind eigentlich ziemliche Heuchler. Wir sind verärgert, dass der Louvre uns die Problembehebung bei der Mona Lisa nicht gestattet. Dabei haben wir uns neulich ganz ähnlich verhalten. In der Ausgabe des TechNet Magazins vom Januar 2008 haben wir einen Artikel über das Verwenden regulärer Ausdrücke in einem Skript geschrieben. Dies ist ein hervorragendes Beispiel für „Ansehen erlaubt, Anfassen aber nicht“: Wir haben Ihnen gezeigt, wie Sie reguläre Ausdrücke zum Identifizieren von Problemen in einer Textdatei verwenden, aber wir haben Ihnen nicht vorgeführt, wie Sie die Probleme beheben. Dumm gelaufen.

Hinweis: Wenn die Scripting Guys im November 2007 den Louvre besucht haben, wie soll dann der Autor dieses Artikels plötzlich über einen Artikel nachgedacht haben, der erst im Januar 2008 im TechNet Magazin erschienen ist? Wow, das ist schon rätselhaft, nicht wahr? Das muss etwas mit dem Zeitunterschied zwischen Redmond und Paris zu tun haben.

Glücklicherweise sind die Scripting Guys im Unterschied zu den Leuten, die den Louvre betreiben, bereit, ihre Fehler zuzugeben. Es war unser Fehler, nur aufzuzeigen, wie Sie eine Textdatei mithilfe von regulären Ausdrücken durchsuchen können. Wir hätten auch erläutern sollen, wie Sie mithilfe von regulären Ausdrücken Ersetzungen vornehmen können. Eigentlich hätten wir Ihnen ein Skript wie in Abbildung 1 zeigen sollen.

Figure 1 Suchen und ersetzen

      Set objRegEx = _
    CreateObject("VBScript.RegExp")

objRegEx.Global = True   
objRegEx.IgnoreCase = True
objRegEx.Pattern = "Mona Lisa"

strSearchString = _
    "The Mona Lisa is in the Louvre."
strNewString = _
    objRegEx.Replace(strSearchString, _
                     "La Gioconda")

Wscript.Echo strNewString 

Hierbei handelt es sich eindeutig um eine recht banale Verwendung regulärer Ausdrücke: Alles, was hier geschieht, ist das Ersetzen aller Instanzen des Zeichenfolgenwerts Mona Lisa durch La Gioconda (Italienisch für „Wo habe ich nur meine Augenbrauen gelassen?“). Zugegebenermaßen hätten wir diese Ersetzung mithilfe der VBScript-Funktion „Replace“ viel einfacher durchführen können. Aber keine Angst: Mit diesem einfachen kleinen Skript wird erläutert, wie Sie Such- und Ersetzungsvorgänge mithilfe regulärer Ausdrücke durchführen. Anschließend lernen Sie einige interessante Anwendungen dieser Ausdrücke kennen.

Wie Sie sehen, ist dieses Skript wirklich nichts Besonderes. Erstellen Sie zunächst eine Instanz des VBScript.RegExp-Objekts, wobei es sich natürlich um das Objekt handelt, das die Verwendung regulärer Ausdrücke innerhalb eines VBScript-Skripts ermöglicht. Nach dem Erstellen des Objekts weisen Sie drei Eigenschaften des Objekts Werte zu:

Global Durch Festlegen dieser Eigenschaft auf „True“ wird dem Skript mitgeteilt, dass es jede Instanz von Mona Lisa im Zieltext sucht und ersetzt. Wenn für Global-Eigenschaft der Wert „False“ festgelegt wäre (der Standardwert), würde das Skript nur die erste Instanz von Mona Lisa suchen und ersetzen.

IgnoreCase Durch Festlegen von IgnoreCase auf „True“ wird dem Skript mitgeteilt, dass die Suche ohne Beachtung der Groß-/Kleinschreibung erfolgen soll. Anders gesagt sollen „mona lisa“ und „Mona Lisa“ identisch behandelt werden. Standardmäßig beachtet VBScript bei der Suche die Groß-/Kleinschreibung, d. h. aufgrund der groß bzw. klein geschriebenen Buchstaben werden „mona lisa“ und „Mona Lisa“ als völlig verschiedene Werte betrachtet.

Pattern Die Pattern-Eigenschaft enthält den gesuchten Wert. In diesem Fall suchen Sie nur nach einem einfachen Zeichenfolgenwert: Mona Lisa.

Als Nächstes weisen Sie den Suchtext einer Variablen namens „strSearchString“ zu:

strSearchString = "The Mona Lisa is in the Louvre."

Dann rufen Sie die Replace-Methode für reguläre Ausdrücke auf und leiten dieser Methode zwei Parameter weiter: den gesuchten Zieltext (die veränderliche Variable strSearchString) und den Ersetzungstext (La Gioconda). Das ist schon alles.

strNewString = objRegEx.Replace(strSearchString, "La Gioconda")

Weiter ist nichts zu tun. Der geänderte Text wird in der Variablen strNewString gespeichert. Wenn Sie jetzt den Wert von strNewString zurückgeben, müssten Sie Folgendes erhalten:

The La Gioconda is in the Louvre.

Die Grammatik ist wahrscheinlich ein wenig fragwürdig, aber Sie erhalten zumindest eine Vorstellung.

Wie oben schon angemerkt, ist das alles gut und schön, doch es ist definitiv zu viel des Guten. Der gleiche Vorgang hätte auch mithilfe der folgenden Codezeilen erzielt werden können (sogar alles in einer Zeile, falls gewünscht):

strSearchString = "The Mona Lisa is in the Louvre."
strNewString = Replace(strSearchString, "Mona Lisa", "La Gioconda")
Wscript.Echo strNewString

Im Folgenden soll untersucht werden, welche Vorgänge mit regulären Ausdrücken möglich sind, die sich mit der Replace-Funktion in VBScript nicht durchführen lassen.

Haben Sie vielleicht eine Idee? Wir haben eine: Die Scripting Guys müssen oft Text von einer Art von Dokument in ein anderes Dokument kopieren. Manchmal funktioniert das ziemlich gut, und manchmal nicht. Wenn es nicht funktioniert, treten oft merkwürdige Probleme mit dem Wortabstand auf, wobei der Text etwa so aussieht:

Myer Ken, Vice President, Sales and Services

Du liebe Güte, wo kommen denn die ganzen Leerstellen her? In diesem Fall ist die Replace-Funktion nur begrenzt anwendbar. Warum? Hier liegt eine scheinbar zufällige Anzahl irrelevanter Leerstellen vor: Zwischen den Wörtern können sich 7, 2 oder vielleicht 6 Leerstellen befinden. Deshalb ist es schwierig, das Problem mit der Replace-Funktion zu beheben. Wenn Sie zum Beispiel versuchen, 2 aufeinander folgende Leerstellen zu suchen (wobei Sie diese 2 durch eine einzige Leerstelle ersetzen), erhalten Sie Folgendes:

Myer Ken, Vice President, Sales and  Services

Das ist zwar besser, aber noch lange nicht ideal. Es gibt eine Möglichkeit, doch dabei ist es erforderlich, eine willkürliche Zahl von Leerstellen zu suchen, angenommen 39, die Ersetzung vorzunehmen, von der Anfangszahl 1 zu subtrahieren, dann 38 Leerstellen zu suchen, die Ersetzung vorzunehmen und so weiter und so fort. Alternativ können Sie das folgende viel einfachere (und benutzerfreundlichere) Skript mit regulären Ausdrücken verwenden:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = " {2,}"

strSearchString = _
"Myer Ken, Vice President, Sales and Services"
strNewString = objRegEx.Replace(strSearchString," ")

Wscript.Echo strNewString

Wie zu den meisten Skripts mit regulären Ausdrücken ist der Schlüssel zu diesem Skript das Muster (Pattern):

objRegEx.Pattern = " {2,}"

Hier wird nach 2 oder mehr aufeinander folgenden Leerstellen gesucht. Woher wissen Sie, dass dieses Muster nach 2 oder mehr Leerstellen sucht? Innerhalb des doppelten Anführungszeichens befindet sich eine einzelne Leerstelle, gefolgt von dieser Konstruktion: {2,}. In einer Syntax mit regulären Ausdrücken stellt dies eine Anweisung zur Suche von mindestens 2 aufeinander folgenden Instanzen des vorhergehenden Zeichens dar (in diesem Fall eine Leerstelle). Doch was ist, wenn 3, 4 oder 937 aufeinander folgende Leerstellen vorhanden sind? Das ist in Ordnung, denn diese werden ebenfalls erfasst. (Falls mindestens 2 Leerstellen, aber nicht mehr als 8 erfasst werden sollen, verwenden Sie die Syntax {2,8}, wobei die 8 die maximale Anzahl Übereinstimmungen angibt.)

Mit anderen Worten, jedes Mal, wenn Sie 2 oder mehr Leerstellen suchen, die aufeinander folgen, werden all diese aufeinander folgenden Leerstellen erfasst und durch eine einzelne Leerstelle ersetzt. Wie wirkt sich dies auf den anfänglich genannten Zeichenfolgenwert mit all den irrelevanten Leerstellen aus? So:

Myer Ken, Vice President, Sales and Services

Es stimmt also doch: Die Scripting Guys können wirklich zu Verbesserungen beitragen. Wenn nur das Personal im Louvre uns die Korrektur der Mona Lisa gestatten würde.

Hier ist ein interessantes und gar nicht ungewöhnliches Szenario. Angenommen Ihr Unternehmen hat ein Telefonverzeichnis, und alle Telefonnummern sind folgendermaßen formatiert:

555-123-4567

Jetzt hat Ihr Chef jedoch beschlossen, dass alle Telefonnummern so formatiert werden sollen:

(555) 123-4567

Wie schaffen Sie es also, die Telefonnummern neu zu formatieren? Wir schlagen vor, Sie verwenden ein ähnliches Skript wie dieses:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\d{3})-(\d{3})-(\d{4})"

strSearchString = "555-123-4567"
strNewString = objRegEx.Replace _
(strSearchString, "($1) $2-$3")

Wscript.Echo strNewString

Hierbei wird nach 3 Ziffern (\d{3}) gesucht, gefolgt von einem Strich, gefolgt von 3 weiteren Ziffern und einem Strich, gefolgt von 4 Ziffern. Kurz gesagt, es wird Folgendes gesucht, wobei jedes X eine Zahl von 0 bis 9 darstellt:

XXX-XXX-XXXX

Hinweis: Woher wussten wir, dass \d{3} dem Skript mitteilen würde, drei Zahlen direkt hintereinander zu suchen? Soweit wir uns erinnern können, haben wir das irgendwo gelesen. Es muss entweder das schockierende Schlusskapitel von „Sakrileg“ oder das Kapitel „VBScript-Sprachreferenz“ auf MSDN® online gewesen sein (siehe go.microsoft.com/fwlink/?LinkID=111387).

Es ist schon toll, dass Sie mit regulären Ausdrücke nach einer beliebigen Telefonnummer suchen können. Sie haben allerdings immer noch ein großes Problem. Schließlich lässt sich diese beliebige Telefonnummer nicht durch eine gleichermaßen beliebige Telefonnummer ersetzen. Sie müssen stattdessen dieselbe Telefonnummer verwenden, die nur etwas anders formatiert wurde. Wie lässt sich dies erreichen?

Ganz einfach mithilfe des folgenden Ersetzungstexts:

"($1) $2-$3"

$1, $2 und $3 sind Beispiele für einen „Rückverweis“ mit regulärem Ausdruck. Ein Rückverweis ist ein Teil des gefundenen Texts, der gespeichert und dann wiederverwendet werden kann. Im vorliegenden Skript suchen Sie nach drei „untergeordneten Übereinstimmungen“:

  • einem Satz von 3 Ziffern
  • einem Satz von weiteren 3 Ziffern
  • einem Satz von 4 Ziffern

Jede dieser untergeordneten Übereinstimmungen wird automatisch einem Rückverweis zugewiesen: Die erste untergeordnete Übereinstimmung ist $1, die zweite ist $2 und so weiter, bis hin zu $9. In diesem Skript werden also die drei Teile der Telefonnummer automatisch den Rückverweisen in Abbildung 2 zugewiesen.

Figure 2 Telefonnummernrückverweise

Telefonnummernteil Rückverweis
555 $1
123 $2
4567 $3

In der Ersetzungszeichenfolge wird durch diese Rückverweise sichergestellt, dass die richtige Telefonnummer wiederverwendet wird. Der Ersetzungstext sagt Folgendes aus: den ersten Rückverweis ($1) in Klammern einschließen. Ein Leerzeichen lassen, dann einen zweiten Rückverweis einfügen ($2), gefolgt von einem Strich. Abschließend den dritten Rückverweis ($3) anfügen.

Was ist das Ergebnis? Eine Telefonnummer, die folgendermaßen aussieht:

(555) 123-4567

Nicht schlecht, gar nicht mal so schlecht.

Hier ist eine andere Version des Telefonnummernskripts. Angenommen Ihre Organisation hat ein brandneues Telefonsystem installieren lassen, sodass nun alle Telefonnummern die gleiche Vorwahl haben. Nummern, die bisher mit 666, 777 oder 888 anfingen, fangen jetzt mit 333 an. Können die Telefonnummern neu formatiert und die Telefonnummernvorwahl gleichzeitig geändert werden? Selbstverständlich:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\d{3})-(\d{3})-(\d{4})"

strSearchString = "555-123-4567"
strNewString = objRegEx.Replace _
(strSearchString,"($1) 333-$3")

Wscript.Echo strNewString

Sehen Sie, was hier geschehen ist? Die alte Vorwahl (Rückverweis $2) im Ersetzungstext wurde einfach entfernt und durch den hartcodierten, und jetzt standardmäßigen, Vorwahlwert 333 ersetzt. Wie sieht die Telefonnummer 555-123-4567 aus, wenn dieses geänderte Skript ausgeführt wird? Sie sieht genau so aus:

(555) 333-4567

Es gibt noch eine andere allgemeine Verwendung für Rückverweise. Angenommen Ihnen liegt dieser Zeichenfolgenwert vor:

Myer, Ken

Gibt es eine Möglichkeit, den Wert zu ändern und den Namen so anzuzeigen:

Ken Myer

Es wäre schon albern, wenn es keine Möglichkeit gäbe. Hier ist ein Skript, das genau dies ausführt:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\S+), (\S+)"

strSearchString = "Myer, Ken"
strNewString = objRegEx.Replace _

strSearchString,"$2 $1")

Wscript.Echo strNewString

Im vorliegenden Skript wird ein Wort, (\S+), gesucht, gefolgt von einem Komma, gefolgt von einer Leerstelle, gefolgt von einem anderen Wort. (In diesem Fall verwenden wir \S+, um ein „Wort“ darzustellen.) Die Konstruktion \S+ steht für einen beliebigen aufeinander folgenden Satz von Nichtleerstellenzeichen. Anders gesagt steht hier ein Buchstabe, eine Zahl oder ein Symbol. Genau genommen könnte hier alles stehen, ausgenommen ein Leerzeichen, ein Tabulatorstopp oder ein Zeilenumbruch. Wie Sie sehen, müssten hier zwei untergeordnete Übereinstimmungen gefunden werden: eine für den Nachnamen ($1) und eine für den Vornamen ($2). Daher kann der Benutzername mithilfe dieser Syntax als „FirstName LastName“ angezeigt werden:

"$2 $1"

Wo ist das Komma? Es war nicht erforderlich, deshalb wurde es einfach wegrationalisiert.

Hinweis: Seltsam, bei dem Vorgang kam uns aus irgendeinem unerfindlichen Grund der Skripting Editor in den Sinn. Hmmm ...

Abschließend folgt noch ein Beispiel, bevor wir uns für heute verabschieden. (Ok, genau genommen bis nächsten Monat.) Es wurde ein wenig vereinfacht, ist daher nicht völlig idiotensicher – ein Einführungsartikel wie dieser soll schließlich nicht zu kompliziert geraten. Reguläre Ausdrücke sind nämlich potenziell außerordentlich komplex ... Dennoch ist hier ein Skript, das – in den meisten Fällen – die Anfangsnullen aus einem Wert wie 0000.34500044 entfernt:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "\b0{1,}\."

strSearchString = _
"The final value was 0000.34500044."
strNewString = objRegEx.Replace _
strSearchString,".")

script.Echo strNewString

Wie bei den obigen Beispielen hängt wieder alles vom Muster ab: "\b0{1,}\." Anfangs wird nach einer Wortbegrenzung (\b) gesucht. So wird sichergestellt, dass die Nullen in einem Wert wie 100.546 nicht entfernt werden. Wir suchen dann nach einer oder mehr Nullen – 0{1,} – gefolgt von einem Dezimalzeichen (\.). Wenn das Muster gefunden wird, werden die Nullen (und das Dezimalzeichen) durch ein einzelnes Dezimalzeichen „.“ ersetzt. Wenn alles nach Plan läuft, wird die Zeichenfolge so umgewandelt:

The final value was .34500044.

Das war schon alles für diesen Monat. Zu guter Letzt möchten wir anmerken, dass die Mona Lisa sozusagen bereits Meinungsverschiedenheiten ausgelöst hat, noch bevor die Farbe auf der Leinwand trocken war. Wer ist diese mysteriöse Frau? Weshalb lächelt sie so? Warum hat sie keine Augenbrauen? Einige Kunsthistoriker behaupten, dass Mona Lisa gar keine Frau ist, sondern ein Selbstporträt von Leonardo da Vinci. (Wenn das wahr ist, sollte er sich wirklich mal einen neuen Schneider suchen.) Inzwischen ist die Unarius Educational Foundation einen Schritt weiter gegangen und hat behauptet, dass das Gemälde tatsächlich die „Zwillingsseele“ von Leonardo in der „höheren Welt“ darstellt, und dass diese Zwillingsseele Leonardos Hand geführt hat. Was für ein bemerkenswerter Zufall, genau so ist der Artikel für diese Ausgabe von „Hey, Scripting Guy!“ entstanden.

Richten Sie Ihre Beschwerden also an die-zwillingsseele-des-scripting-guys-der-diesen-artikel-schreibt@das-andere-microsoft.com. Vielen Dank.

Der Scripting Perplexer von Dr. Scripto

Die monatliche Herausforderung, die nicht nur Ihr Talent zum Rätsellösen testet, sondern auch Ihre Skriptingfähigkeiten.

Mai 2008: Skriptdoku

Diesen Monat wird Sudoku gespielt, aber mit einer kleinen Raffinesse. Anstelle der Zahlen 1 bis 9 im Raster stehen die Buchstaben und Symbole, die ein Windows PowerShell™-Cmdlet ausmachen. In der Auflösung wird in einer der horizontalen Zeilen der Name des Cmdlet buchstabiert.

Hinweis: Wenn Sie nicht wissen, wie Sudoku gespielt wird, finden Sie im Internet vermutlich mehrere tausend Websites mit Anleitungen dazu, sodass wir uns die Regeln hier wirklich ersparen können.

ANSWER:

Der Scripting Perplexer von Dr. Scripto

Antwort: Skriptdoku, Mai 2008

Die Scripting Guys von Microsoft arbeiten für Microsoft (oder sind zumindest dort angestellt). Wenn sie nicht gerade ihrem Hobby, dem Baseball (oder verschiedenen anderen Aktivitäten) nachgehen, betreiben sie das TechNet-Skriptcenter. Besuchen Sie es unter www.scriptingguys.com.

© 2008 Microsoft Corporation und CMP Media, LLC. Alle Rechte vorbehalten. Die nicht genehmigte teilweise oder vollständige Vervielfältigung ist nicht zulässig.