User Tools

Site Tools


vba:tutorials:regexpreplacewithfunction

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
vba:tutorials:regexpreplacewithfunction [26.11.2014 15:07:22]
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 ======
-Najader Titel ist ev. irreführend. Mir kahm aber kein besserer in den Sinn. +//Ein Tutorial zum Themawie 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>​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>​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>
  
vba/tutorials/regexpreplacewithfunction.1417010842.txt.gz · Last modified: 26.11.2014 15:07:22 by yaslaw