This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
vba:tutorials:regexpreplacewithfunction [26.11.2014 15:07:55] yaslaw |
vba:tutorials:regexpreplacewithfunction [19.10.2015 15:59:17] (current) yaslaw |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== [VBA][Code Pattern] RegExp Replace mit Funktion ====== | ====== [VBA][Code Pattern] RegExp Replace mit Funktion ====== | ||
- | Naja, der Titel ist ev. irreführend. Mir kahm aber kein besserer in den Sinn. | + | //Ein Tutorial zum Thema, wie man eine %%RegExp Replace%% in einer Schleife anwenden kann.// |
- | \\ Es geht um folgendes: Mittels eines %%RegExp%% ermittle ich Teilstrings. Diese sollen über eine Funktion verändert werden und dann im String den Originalteilstring ersetzen. | + | |
+ | Naja, der Titel ist ev. irreführend. Mir kahm aber kein besserer in den Sinn. Es geht um folgendes: Mittels eines %%RegExp%% ermittle ich Teilstrings. Diese sollen über eine Funktion verändert werden und dann im String den Originalteilstring ersetzen. | ||
+ | |||
+ | ===== Beispielsaufgabe ===== | ||
Ein kleines Beispiel: den folgende String | Ein kleines Beispiel: den folgende String | ||
- | \\ ''Bären und Hüner gehören nicht in Ämter'' | + | <code>Bären und Hühner gehören nicht in Ämter</code> |
- | \\ Jetzt will ich alle äöü und ÜÖÜ in Unicode setzen | + | Jetzt will ich alle äöü und ÜÖÜ in Unicode setzen |
- | \\ ''B\u00E4ren und H\u00FCner geh\u00F6ren nicht in \u00C4mter'' | + | <code>B\u00E4ren und H\u00FChner geh\u00F6ren nicht in \u00C4mter</code> |
Dazu habe ich mal die Funktion [[vba:cast:char2unicode]], welche mir einen einzelnen Char nach Unicode wandelt. | Dazu habe ich mal die Funktion [[vba:cast:char2unicode]], welche mir einen einzelnen Char nach Unicode wandelt. | ||
+ | ===== Umsetzungen ===== | ||
Mit %%RegExp.replace()%% kann ich bekanntlich keine User-Funktion ausführen. Darum löse ich das meistens wie folgt. | Mit %%RegExp.replace()%% kann ich bekanntlich keine User-Funktion ausführen. Darum löse ich das meistens wie folgt. | ||
> Für die Ausgabe der Resultate verwendete ich die Funktion [[vba:functions:print_r:index]] | > Für die Ausgabe der Resultate verwendete ich die Funktion [[vba:functions:print_r:index]] | ||
+ | ==== Konzept ==== | ||
+ | Ich erstelle ein %%RegExp%%-Objekt, das genau nur ein Treffer zurückgibt (global=off). Mit einer Schleife teste ich auf den String, ob %%RegExp%% noch einen Treffer hat. | ||
+ | |||
+ | Jeder Treffer wird ausgelesen. Mittels einer UDF (User Defined Function) kann man mit dem gefundenen String oder Submatches etwas machen | ||
+ | |||
+ | Anschliessend nutze ich der %%RegExp%%.replace() um den Teilstring im Original durch den Neuen zu ersetzen | ||
+ | |||
+ | Das ganez wiederholen bis keine Treffer mehr da sind | ||
+ | |||
+ | ==== Einschränkung ==== | ||
+ | Es funktioniert natürlich nicht, wenn der neue String wieder dem Pattern entspricht. Wenn ich also bei %%IgnoreCase%% ''A'' durch ''a'' ersetzen will, landet das ganze in einer Endlosschleife. | ||
+ | |||
==== Version 1) Funktion mit detailiertem Aufbau ==== | ==== Version 1) Funktion mit detailiertem Aufbau ==== | ||
=== Beispielsfunktion replUmlaute() mit detailiertem Aufbau === | === Beispielsfunktion replUmlaute() mit detailiertem Aufbau === | ||
- | Die folgende Umsetzung beinhaltet eigentlich bereits die ganze Logik. Zum besseren Verständnis sind noch alle Schritte einzel auugeführt | + | Die folgende Umsetzung beinhaltet eigentlich bereits die ganze Logik. Zum besseren Verständnis sind noch alle Schritte einzel auugeführt. Die Erklärung ist im Code mit drin. |
<code vb>Public Function replUmlaute(ByVal iString As String) As String | <code vb>Public Function replUmlaute(ByVal iString As String) As String | ||
- | Static rx As regExp 'Das RegExp als Statisch definieren, damit es nicht bei jedem AUfruf initialisiert werden muss | + | 'Das RegExp als Statisch definieren, damit es nicht bei jedem Aufruf initialisiert werden muss |
+ | Static rx As regExp | ||
Dim mc As MatchCollection | Dim mc As MatchCollection | ||
Dim m As match | Dim m As match | ||
Line 27: | Line 43: | ||
rx.pattern = "([äöü])" | rx.pattern = "([äöü])" | ||
rx.IgnoreCase = True | rx.IgnoreCase = True | ||
- | 'Die folgedne Zeile müsste ich eigentlich nicht setzen. | + | 'Die folgende Zeile müsste ich eigentlich nicht setzen. |
'Aber es ist Wichtig, dass Global nicht auf True ist. | 'Aber es ist Wichtig, dass Global nicht auf True ist. | ||
rx.Global = False | rx.Global = False | ||
Line 45: | Line 61: | ||
unicode = char2unicode(sm(0)) | unicode = char2unicode(sm(0)) | ||
'und den ersten Treffer mittels RegExp ersetzen | 'und den ersten Treffer mittels RegExp ersetzen | ||
+ | 'Dank global=off gibts nur den einen Treffer zu ersetzen | ||
replUmlaute = rx.Replace(replUmlaute, unicode) | replUmlaute = rx.Replace(replUmlaute, unicode) | ||
Loop | Loop | ||
End Function</code> | End Function</code> | ||
=== Test der Funktion === | === Test der Funktion === | ||
- | <code vb>d replUmlaute("Bären und Hüner gehören nicht in Ämter") | + | <code vb>d replUmlaute("Bären und Hühner gehören nicht in Ämter") |
- | <String> 'B\u00E4ren und H\u00FCner geh\u00F6ren nicht in \u00C4mter'</code> | + | <String> 'B\u00E4ren und H\u00FChner geh\u00F6ren nicht in \u00C4mter'</code> |
==== Version 2) Kompakte Version ==== | ==== Version 2) Kompakte Version ==== | ||
- | In dieser Version verzichte ich darauf, alle Schritte einzeln durchzugehen. Auch das ertellen des %%RegExp%% überlasse ich der Funktion [[vba:cast:cregexp#Abgespeckte Version|[VBA] cRegExp() Abgespeckte Version]]. Dann sieht der Code noch so aus. | + | In dieser Version verzichte ich darauf, alle Schritte einzeln durchzugehen. Auch das ertellen des %%RegExp%% überlasse ich der Funktion [[vba:cast:cregexp#abgespeckte_version_crx|[VBA] cRegExp() Abgespeckte Version]]. Dann sieht der Code noch so aus. |
Ja, der erste ist besser lesbar. Wenn an aber ein Pattern immer wieder verwendet, erkennt man es beim lesen vom Code sofort. | Ja, der erste ist besser lesbar. Wenn an aber ein Pattern immer wieder verwendet, erkennt man es beim lesen vom Code sofort. | ||
Line 67: | Line 84: | ||
=== Test der Funktion replUmlaute() === | === Test der Funktion replUmlaute() === | ||
- | <code vb>d replUmlaute("Bären und Hüner gehören nicht in Ämter") | + | <code vb>d replUmlaute("Bären und Hühner gehören nicht in Ämter") |
- | <String> 'B\u00E4ren und H\u00FCner geh\u00F6ren nicht in \u00C4mter'</code> | + | <String> 'B\u00E4ren und H\u00FChner geh\u00F6ren nicht in \u00C4mter'</code> |
=== Beispielsfunktion replUmlauteBack() kompakt === | === Beispielsfunktion replUmlauteBack() kompakt === | ||
Line 82: | Line 99: | ||
=== Test der Funktion replUmlauteBack() === | === Test der Funktion replUmlauteBack() === | ||
- | <code vb>d replUmlauteBack("B\u00E4ren und H\u00FCner geh\u00F6ren nicht in \u00C4mter") | + | <code vb>d replUmlauteBack("B\u00E4ren und H\u00FChner geh\u00F6ren nicht in \u00C4mter") |
- | <String> 'Bären und Hüner gehören nicht in Ämter'</code> | + | <String> 'Bären und Hühner gehören nicht in Ämter'</code> |
===== Beipiele in Action ===== | ===== Beipiele in Action ===== | ||
In den [[vba:cast:json]] setze ich dieses Pattern mehrfach ein. | In den [[vba:cast:json]] setze ich dieses Pattern mehrfach ein. | ||
+ | ===== Anhänge ===== | ||
+ | ==== Anhang A: Code cRegExp() ==== | ||
+ | <code vb cregexp.bas>'/** | ||
+ | ' * Erstellt ein RegExp-Object mit den Grundeinstellungen | ||
+ | ' * V2.0.1 | ||
+ | ' * @param String Pattern mit Delmiter und igm-Parametern | ||
+ | ' * @return RegExp | ||
+ | ' */ | ||
+ | Private Function cRegExp(ByVal iPattern As String) As Object | ||
+ | Static rxP As Object 'RegExpo um iPattern aufzubrechen | ||
+ | If rxP Is Nothing Then | ||
+ | Set rxP = CreateObject("VBScript.RegExp") | ||
+ | rxP.pattern = "^([@&!/~#=\|])(.*)\1(?:([Ii])|([Gg])|([Mm]))*$" | ||
+ | End If | ||
+ | Set cRegExp = CreateObject("VBScript.RegExp") 'Neuer RegExp erstellen | ||
+ | If Not rxP.Test(iPattern) Then cRegExp.pattern = iPattern: Exit Function 'Falls es ein einfacher Pattern ist, diesen übernehmen und die Func verlassen | ||
+ | Dim parts As Object: Set parts = rxP.execute(iPattern)(0).subMatches 'Pattern zerlegen. 0) Delemiter, 1) Pattern, 2) - 4) Paramters | ||
+ | cRegExp.IgnoreCase = Not isEmpty(parts(2)) | ||
+ | cRegExp.Global = Not isEmpty(parts(3)) | ||
+ | cRegExp.Multiline = Not isEmpty(parts(4)) | ||
+ | cRegExp.pattern = parts(1) | ||
+ | End Function</code> | ||
+ | |||
+ | ==== Anhang B: Code char2unicode() ==== | ||
+ | <source '/vba/cast/cast_char2unicode.bas' vb> | ||
+ | ==== Anhang C: Code unicode2char() ==== | ||
+ | <source '/vba/cast/cast_unicode2char.bas' vb> | ||