Regular Expressions von 0 an

    • Allgemein

    Es gibt 1 Antwort in diesem Thema. Der letzte Beitrag () ist von LaMiy.

      Regular Expressions von 0 an

      Da immer noch sehr viele Leute RegularExpressions nicht beherrschen, und das meiner Meinung daran liegt, dass die anderen Tutorials wie ein riesiger Klumpen Wissen wirken, mache ich hier mal ein wirklich kleines Tutorial, mit dem man in 80% der Fälle keine Probleme beim Auslesen von Texten etc. hat. Wenn man es ganz liest, was denke ich ca. 10 Minuten dauert, ist man schon einen großen Schritt weiter in Regular Expression und kann sich weitere Tutorials angucken.

      Der Anfang
      Dann fangen wir auch mal direkt an.
      Wie erstelle ich RegularExpressions in VB ?
      Zuerst schalte ich Option Strict ON und importiere System.Text.RegularExpressions

      Ein normaler RegEx ist so aufgebaut:

      VB.NET-Quellcode

      1. Private Sub RegularExpression_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      2. Dim input As String = "Das ist ein Test"
      3. Dim r As New Regex("...")
      4. Dim matches As MatchCollection = r.Matches(input)
      5. For Each m As Match In matches
      6. MessageBox.Show(m.Value)
      7. Next
      8. End Sub

      Zur Erläuterung. Wir haben einen normalen String. Dann erstellen wir eine neue Instanz der RegularExpressions-Klasse. Diese fordert als Parameter ein Suchpattern. Das Pattern ist unser Suchmuster, mitdem im Text gesucht wird, wobei wir in der nächsten Zeile sind, denn da wird eine MatchCollection angelegt, nämlich die "Übereinstimmungen", auf die unser Suchmuster passt. Kurz: alle gefundenen Matches werden zusammengefasst. Dann schleife ich durch diese Collection und erhalte einzelne Matches. Anschließend gebe ich diesen Match aus.

      Das NonPlusUltra

      Bevor wir richtig anfangen würde ich gerne noch einen Tipp von mir in die Runde werfen. Oft hat man Probleme mit Zeilenumbrüchen, denn diese blockieren manchmal das Suchpattern und man muss das extra handeln. Ich replace einfach immer alle Zeilenumbrüche: text = text.Replace(vbCrLf, "") 'oder Enviroment NewLine Vorab: In Regular Expressions gibt es "Zeichen" die für etwas stehen. Der Punkt steht zum Beispiel für ein beliebiges Zeichen.

      So nun geht es aber los. Ich sage in diesem Abschnitt nur etwas zu den Suchpattern.
      Ich arbeite recht viel mit RegEx und das, was ich am meisten benutze ist das Suchmuster: (.*?)x
      Es findet alles bis "x". Ein Punkt ist nämlich ein beliebiges Zeichen und Stern findet alle Vorkommen ab der Anzahl 0. Das Fragezeichen sagt "bis zum ersten vorkommen, von dem Zeichen oder Wort was danach kommt". Ein konkretes Beispiel: "Das ist ein kleiner Text" (.*?)k findet nun "Das ist ein k" Wieso? Weil das Suchmuster "alles" bis zum ersten Vorkommen von "k" findet.

      Oftmals hat man mit HTML-Text zu tun. Angenommen man will nun von einer Seite etwas auslesen und ein Teil des Quelltexts sieht so aus:

      Quellcode

      1. <div id="test">Aktueller Dax: 0,01</div>

      Hier muss ich allerdings aufpassen, ob dieser Teil des Quelltexts nicht zweimal vorkommt, denn dann habe ich das Problem das ich eventuell zwei Ergebnisse erhalte. Wir haben nun unseren Ausdruck (.*?) und wollen den Text zwischen den Divs haben.
      Also schreiben wir "<div id="test"(.*?)<.div>" (Den Punkt im schließenden div-Tag habe ich gemacht, weil in RegEx Slashes und Backslashes speziell behandelt werden) Wenden wir nun dieses Suchmuster an bekommen wir "<div id="test">Aktueller Dax: 0,01</div>" zurück. Das heißt er hat es auf jeden Fall gefunden. Jetzt haben wir aber noch diesen ganzen Div-Kram um unseren Text.
      Damit kommen wir zu:

      Groups

      Groups sind wie der Name sagt "Gruppen".
      Und zwar haben wir ja unser Beispielpattern "<div id="test"(.*?)<.div>" es findet "<div id="test">Aktueller Dax: 0,01</div>". Wir haben in unsrem Suchmuster ja zuerst den Anfangstext angegeben und danach den Endtext. Das dazwischen soll unser Ergebnis sein, das heißt dann "übersetzt" (.*?) ist unser Ergebnis. Nur wie kommen wir jetzt daran ? Dafür gibt es eben Groups Diese sehen wie folgt aus: (?<dernamedergruop>) Nach dieser Struktur versuchen wir mal die Group in unser Beispiel einzubauen. "<div id="test"(?<text>(.*?))<.div>" In "text" sollte nun unser Text stehen.
      So müssen wir Groups in VB ansprechen: MessageBox.Show(matches(0).Groups("text").Value) Also Match.Groups("namedergroup").Value gibt unsere Group aus. In dem Fall erhalten wir "Aktueller Dax: 100"

      Eingrenzungen und Anzahl

      Angenommen unser Text ist nun "<div id="test">Aktueller Dax: 100</div>" Nun wollen wir nur die Zahl und nicht den Text davor. Dazu können wir eingrenzen. "[]" also eckige Klammern machen das zum einen.
      Unser Suchmuster ist: "Aktueller Dax:.(.*?[0-9])" 0-9 heißt, dass Zahlen gefunden werden sollen. Mit diesem Pattern finden wir "Aktueller Dax: 1" Wir wollen aber nun 100 und nicht 1. Dazu können wir {} also geschweifte Klammern einsetzten. Diese sagen nämlich wie oft der der Teil des Suchmusters vorkommen kann oder soll. Sie sind so aufgebaut: "{min, max}" Also mindestens "x" Ziffern, maximal "y" Ziffern. (Nur in diesem Beispiel, bei [a-z] , also alle Buchstaben, würde es die Anzahl der Zeichen angeben) Dieses Suchmuster ergibt sich: "Aktueller Dax:.(.*?[0-9]{0,7})" In Sprache übersetzt heißt das: Finde alles nach "Aktueller Dax", was eine Zahl ist und maximal sieben Ziffern lang ist. In der Tat findet es "Aktueller Dax: 100" Wir wollen aber nur die 100, also wenden wir unsere Group an und grenzen es ein.
      So sieht dann das Pattern aus: "Aktueller Dax:.(?<zahl>(.*?[0-9]{0,7}))" Und in der Tat findet MessageBox.Show(matches(0).Groups("zahl").Value) das Ergebnis 100.

      Schlusswort und Zusammenfassung
      Was haben wir gemacht und welche Zeichen haben wir behandelt ?
      Wir haben x(.*?)x benutz um alles von x bis x zu funden. Denn:
      "Punkt" ist ein beliebiges Zeichen
      "Stern" ist die Anzahl ab 0. Das heißt "jeder Punkt", also "jedes beliebige Zeichen" wird gefunden.
      "Fragezeichen" bis zu einem bestimmten Punkt. Dieser "Punkt" muss danach stehen. In dem Fall das "x"
      Dann haben wir Groups benutz. "(?<name>(.*?))" Wir haben also (.*?) einer Gruppe zugeordnet.
      Zum Schluss haben wir das Ganze mit [] und {} eingegrenzt. Also gesagt (.*?) soll eine Zahl sein "[0-9]" und soll maximal x Zeichen lang sein "{0, x}"

      Zum Schluss ist zu sagen, dass man alle Sachen in diesem Tutorial mal selbst ausprobieren sollte um zu sehen was passiert.
      Man muss ein bisschen kreativ sein und versuchen gute Strukturen im Text zu finden, also Sachen woran man das Gesuchte "ferstmachen" kann´. Dann ist es kein Problem auch größere Texte mit Regular Expressions zu bearbeiten. Natürlich war das nur ein winziger Teil dieser sehr mächtigen Möglichkeiten. Weitere "Suchzeichen" könnt ihr hier finden.

      Was bringt uns das alles nun ?
      Wir können jetzt zum Beispiel den Titel jedes beliebigen YouTube Videos auslesen :)

      VB.NET-Quellcode

      1. Imports System.Text.RegularExpressions
      2. Public Class Form1
      3. Private WithEvents w As New Net.WebClient
      4. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      5. w.DownloadStringAsync(New Uri("http://www.youtube.com/watch?v=qMmf7gQePf8"))
      6. End Sub
      7. Private Sub w_DownloadStringCompleted(ByVal sender As Object, ByVal e As System.Net.DownloadStringCompletedEventArgs) Handles w.DownloadStringCompleted
      8. Dim result As String = e.Result
      9. result = result.Replace(vbCrLf, "")
      10. Dim r As New Regex("<meta property=.og:title. content=.(?<title>(.*?)).>")
      11. Dim matches As MatchCollection = r.Matches(result)
      12. MessageBox.Show(matches(0).Groups("title").Value)
      13. End Sub
      14. End Class[/spoiler]

      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „LaMiy“ ()

      Es kam der Wunsch, oder besser gesagt, Gedanke auf mal zu erklären was man unter "escapen" versteht beziehungsweise wieso manche Suchpattern nicht funktionieren wenn man Sonerzeichen oder genauer gesagt Zeichen mit einbezieht, die in RegEx eine Funktion haben. (Beispiel: [VB 2012] Regex )

      Hier also eine kleine Editierung zum Thema
      "Escapen"

      Fangen wir mit einem Beispiel an.
      Schreiben wir diesen Code,

      VB.NET-Quellcode

      1. Dim s As String = "php?=bla"
      2. Dim matches As MatchCollection = New Regex("?(.*)").Matches(s)
      3. MessageBox.Show(matches(0).Value)

      bekommen wir folgenden Fehler: ""?(.*)" wird analysiert - Quantifizierer {x,y} nach nichts."
      Wieso ? Weil das Fragezeichen ("?") in RegEx für "bis zum ersten Vorkommen von x steht"
      Unser Pattern ergibt also "keinen Sinn".
      Escapen wir nun das Fragezeichen mit einem Backslash, bekommen wir das gewünschte Ergebnis.
      Fazit. Wir müssen also jedes Zeichen, nach welchem wir suchen wollen, und was in RegEx eine Bedeutung hat durch einen Backslash davor "escapen", also markieren.
      ... -> \.\.\.
      ? -> \?
      * -> \*
      usw ...


      Kurzschreibweisen für Platzeinsparung.

      VB.NET-Quellcode

      1. For Each m As Match In New Regex("id=(?<id>(.*[0-9]{2}))").Matches("php?id=50")
      2. MessageBox.Show(m.Groups("id").Value)
      3. Next

      MessageBox.Show(New Regex("id=(?<id>(.*[0-9]{2}))").Match("php?id=50").Groups("id").Value)

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „LaMiy“ ()