Brauche Hilfe bei Regex

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Eierlein.

    Brauche Hilfe bei Regex

    Heyho Community,

    ich habe ein Problem mit Regex, ich verstehe nicht wirklich wie das mit den Backslash's etc. Funktioniert...
    Ich möchte gerne aus dem Quelltext einer Seite die ich via. HTTPWebRequest bekommen habe und in einem String zwischen gespeichert habe
    einen link filtern.
    Jedoch nicht einfach den Link sondern muss dieser etwas. bestimmtes beinhalten.

    HTML Code des Links sieht ca. so aus:

    HTML-Quellcode

    1. <img src="http://server1.domain.de/ID/IDv2/22/blabla-blaa_dde-dde.png?fullpic" alt="" height="150" width="115">

    Und ich möchte NUR die Links rausfiltern und in einem label/string ausgeben lassen die das "server1" hinter dem http:// haben!

    Wäre nett wenn mir einer Helfen könnte bzw. mir jemand eine Seite schicken könnte wo diese /w etc. klamotten erläutert werden!

    MfG und Danke im vorraus ;)
    Hier mal ohne RegEx

    VB.NET-Quellcode

    1. Sub main()
    2. Dim text As String = "<img src=" & Chr(34) & "http://server1.domain.de/ID/IDv2/22/blabla-blaa_dde-dde.png?fullpic" & Chr(34) & " alt=" & Chr(34) & Chr(34) & " height=" & Chr(34) & "150" & Chr(34) & "width=" & Chr(34) & "115" & Chr(34) & ">" & vbCrLf &
    3. "<img src=" & Chr(34) & "http://server1.domain.de/ID/ID/blabla-blaa_dde-dde.png?fullpic" & Chr(34) & " alt=" & Chr(34) & Chr(34) & " height=" & Chr(34) & "150" & Chr(34) & "width=" & Chr(34) & "115" & Chr(34) & ">" & vbCrLf &
    4. "<img src=" & Chr(34) & "http://server1.domain.de/ID/IDv2/22/blabde.png?fullpic" & Chr(34) & " alt=" & Chr(34) & Chr(34) & " height=" & Chr(34) & "150" & Chr(34) & "width=" & Chr(34) & "115" & Chr(34) & ">"
    5. Dim tmp As String = String.Empty
    6. For Each element As String In GetLinks(text)
    7. tmp &= element & vbCrLf
    8. Next
    9. MsgBox(tmp)
    10. tmp = String.Empty
    11. Dim pfad As String = IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "index.html")
    12. For Each element As String In GetLinks(New IO.FileStream(pfad, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.None))
    13. tmp &= element & vbCrLf
    14. Next
    15. MsgBox(tmp)
    16. End Sub
    17. 'Links aus string filtern
    18. Public Function GetLinks(ByVal Text As String, Optional ByVal Filter As String = "http://server1") As List(Of String)
    19. Dim RetVal As New List(Of String)
    20. Dim tmpLine As String = String.Empty
    21. Using sr As New IO.StreamReader(New IO.MemoryStream(System.Text.Encoding.Default.GetBytes(Text)))
    22. Do Until sr.EndOfStream
    23. tmpLine = sr.ReadLine
    24. If tmpLine.ToLower.Contains(Filter.ToLower) Then
    25. For Each s As String In tmpLine.Split(Chr(34))
    26. If s.StartsWith("http://") Then
    27. RetVal.Add(s)
    28. Exit For
    29. End If
    30. Next
    31. End If
    32. Loop
    33. End Using
    34. Return RetVal
    35. End Function
    36. 'Links aus Datei filtern
    37. Public Function GetLinks(ByVal File As IO.FileStream, Optional ByVal Filter As String = "http://server1") As List(Of String)
    38. Dim RetVal As New List(Of String)
    39. Dim tmpLine As String = String.Empty
    40. Using sr As New IO.StreamReader(File)
    41. Do Until sr.EndOfStream
    42. tmpLine = sr.ReadLine
    43. If tmpLine.ToLower.Contains(Filter.ToLower) Then
    44. For Each s As String In tmpLine.Split(Chr(34))
    45. If s.StartsWith("http://") Then
    46. RetVal.Add(s)
    47. Exit For
    48. End If
    49. Next
    50. End If
    51. Loop
    52. End Using
    53. Return RetVal
    54. End Function
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D
    1.: Chr(34) => geht genauso über doppeltes "

    VB.NET-Quellcode

    1. str = "Ein "" umschließ Strings" ' Besser Lesbar? Für Leute die die Ascii-Tabelle nicht kennen?


    2.: PAN möchte vielleicht wissen, was du da tust.
    Einen so aufgebauten Quelltext einfach zu lesen hilft nicht weiter, wenn er dennoch nicht versteht was da steht.
    Kommentare?

    Hier mal eine kürzere, Rekursieve Methode (Ungetestet!)

    VB.NET-Quellcode

    1. ' [...]
    2. Dim links As New List(Of String)
    3. Dim linkPattern As String = "http//server1" ' Was suchst du?
    4. Dim text As String = "bla" & vbCrLf & "blub" ' Hier würde dein Seitenquellcode stehen
    5. Dim lines() As String = text.Split(CChar(vbCrLf)) ' Hier wird dein Quelltext in einen Stringarray gesplittet (immer am Cariage Return bzw. LineFeed)
    6. For Each line As String In lines ' Jede Zeile durchiterieren
    7. If Not line.Contains(linkPattern) Then Continue For ' Nächste zeile wenn Pattern nicht enthalten
    8. links.AddRange(GetLinksInLine(line, linkPattern))
    9. Next
    10. End Sub
    11. Private Function GetLinksInLine(line As String, pattern As String) As List(Of String)
    12. Dim links As New List(Of String)
    13. If Not line.Contains(pattern) Then Return links ' Wenn das Pattern nicht enthalten ist, wird hier abgebrochen
    14. ' Nach dem Anfang vom Pattern suchen und den restlichen String rauskopieren
    15. Dim linkBegin As String = line.Substring(line.IndexOf(pattern))
    16. ' Das nächste " markiert das Ende des String
    17. Dim endPos As Integer = linkBegin.IndexOf(""""c) ' Stellt ein einzelnes " dar
    18. Dim nextLink As String = linkBegin.Substring(endPos) ' Rest des Strings kopieren
    19. links.Add(linkBegin.Substring(0, endPos)) ' Link rausgefiltert
    20. ' Rekursiever Aufruf, wenn bspw. 3 Links in der Zeile sind
    21. links.AddRange(GetLinksInLine(line, pattern))
    22. Return links
    23. End Function


    Das da kein Methoden-Anfang steht liegt daran, dass ich grad einfach nen Unit-Test dafür Missbraucht hab ^^

    PS: Biederman, deine Funktionen machen genau das selbe, vielleicht wäre hier eine gemeinsam genutzte Methode Sinnvoller? Du müsstest sie nur mit dem entsprechenden Streamreader aufrufen ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kagurame“ ()

    Kagurame schrieb:

    1.: Chr(34) => geht genauso über doppeltes "

    Das ist mir bewusst, aber bei drei oder vier Anführungszeichen verliert man leicht den Überblick.

    Normalerweise benutze ich eine Konstante dafür:

    VB.NET-Quellcode

    1. const QTE as Char = Chr(34)


    Weil ich finde, dass bei folgendem

    VB.NET-Quellcode

    1. dim s as string = "Hallo " & QTE & QTE & QTE & "Franz" & QTE & QTE & QTE

    viel deutlicher erkennbar ist, wie viele Anführungszeichen vorhanden sind als bei

    VB.NET-Quellcode

    1. Dim s2 As String = "Hallo """"""Franz"""""""



    Die zwei Methoden sind nur zur Veranschaulichung. 1) Falls er einen String bekommt und 2) Falls er eine Datei ausliest. Daraus muss er sich halt das basteln was er benötigt.


    Für was man bei einem einfachen Text eine rekursive Methode braucht, ist mir allerdings Rätselhaft...
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D

    BiedermannS schrieb:

    Das ist mir bewusst, aber bei drei oder vier Anführungszeichen verliert man leicht den Überblick.

    Drei oder vier braucht man in aller Regel ja selten

    BiedermannS schrieb:

    wie viele Anführungszeichen vorhanden sind als bei

    Geht trotzdem übersichtlicher, bzw. besser. Zum Strings zusammenbastel gibt es eine entsprechende Funktion:

    VB.NET-Quellcode

    1. Dim myString = String.Format("Hallo {0}{0}{0}Franz{0}{0}{0}", """")

    Wird intern auch sauberer gerelt als der Ampersand in der Masse.

    BiedermannS schrieb:

    Für was man bei einem einfachen Text eine rekursive Methode braucht, ist mir allerdings Rätselhaft...

    Rekursionen nehmen in vielen Fällen einiges an Arbeit weg, wenn die Alternative eine Schleife ist.
    Rein Theoretisch funktioniert meine Rekursion oben auch mit dem gesamten Quelltext ungesplittet, der Vorteil ist, dass ich mich in keinster Weise drum kümmern muss wie oft ich durchgehen muss, sprich ich muss mich auch nicht drum kümmern heraus zu finden, wie viele dieser Links nun da drin stecken.

    Wenn du es mit deinem Code vergleichst, dürfte der Vorteil an zu schreibendem Code wohl auffallen.
    Natürlich, es ist nur eine Funkion, aber was ist, wenn du mehrere solcher Dinge brauchst? Wenn du das Ding 1000 mal durchlaufen musst?

    1000 mal 8 Zeilen sind schneller durchgeführt als deine 16, welche noch viel BackEnd haben durch das Using und deine Streams (Im Falle eines Strings). Selbst wenn es eine Datei ist, hau ich einfach den Stream selbst in Textform rein.

    Kagurame schrieb:

    Rekursionen nehmen in vielen Fällen einiges an Arbeit weg, wenn die Alternative eine Schleife ist.

    Rekursionen sind hilfreich wenn eine Baumstruktur vorliegt, welche durchsucht wird, oder das Ergebnis der Berechnung der Anfangswert einer neuen Berechnung sein soll. Ist aber bei einer einfachen Textsuche nicht erforderlich.

    Kagurame schrieb:

    Rein Theoretisch funktioniert meine Rekursion oben auch mit dem gesamten Quelltext ungesplittet, der Vorteil ist, dass ich mich in keinster Weise drum kümmern muss wie oft ich durchgehen muss, sprich ich muss mich auch nicht drum kümmern heraus zu finden, wie viele dieser Links nun da drin stecken.

    Seit wann muss man sich beim StreamReader und ner List(Of ) um die Anzahl kümmern? Das läuft eh dynamisch.

    Den einzigen Vorteil den ich sehe, ist dass bei deiner Methode auch zwei Links in einer Zeile gefunden werden.

    Kagurame schrieb:

    Wenn du es mit deinem Code vergleichst, dürfte der Vorteil an zu schreibendem Code wohl auffallen.
    Natürlich, es ist nur eine Funkion, aber was ist, wenn du mehrere solcher Dinge brauchst? Wenn du das Ding 1000 mal durchlaufen musst?

    Seit wann ist die Geschwindigkeit eines Programmes direkt proportional zu der Anzahl der Zeilen?

    Und das Nächste: Deine Funktion legt für jeden Durchlauf (Link) eine neue List(of String) an. Also lassen wir das mit der Geschwindigkeit mal weg. Wenn du schon performant sein willst, dann schick die List(of) ByRef mit anstatt immer eine neue anzulegen.

    Kagurame schrieb:

    1000 mal 8 Zeilen sind schneller durchgeführt als deine 16, welche noch viel BackEnd haben durch das Using und deine Streams (Im Falle eines Strings). Selbst wenn es eine Datei ist, hau ich einfach den Stream selbst in Textform rein.

    Den Overhead, den ich produziere kann man durchaus verkraften, wenn man dafür etwas an komfort dazugewinnt. Nämlich das Zeilenweise lesen.
    und überhaupt wird die Datei sowieso nur einmal gelden und danach verarbeitet.

    Wenn du kurzen Code willst:

    VB.NET-Quellcode

    1. Dim reg As New System.Text.RegularExpressions.Regex("\" & Chr(34) & Text.RegularExpressions.Regex.Escape("http://server1") & "[" & Text.RegularExpressions.Regex.Escape("/._?") & "\-a-zA-Z0-9]+\" & Chr(34))
    2. Dim mystring As String = IO.File.ReadAllText(IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "index.html"))
    3. Dim tmp As New Text.StringBuilder()
    4. For Each m As Text.RegularExpressions.Match In reg.Matches(mystring)
    5. tmp.AppendLine(m.Value)
    6. Next
    7. MsgBox(tmp.ToString)


    Sind genau 3 Codezeilen zum Filtern, der Rest ist für die Ausgabe
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „BiedermannS“ ()