VisualBasic RegEx - Split Problem...

dani4u

Ensign
Registriert
Mai 2008
Beiträge
249
Hallo allerseits,

nach einiger zeit googeln und lesen bin ich immernoch nicht auf den trichter gekommen, wie man "richtig" splitted... Irgendwie klappts einfach nicht. Ich bekomme ja ergebnisse raus, doch da hängen eben unerwünschte zeichen dran.

Kann mir wer da fix helfen und kurz erklären warum es so gemacht wird?


Problemstellung: HTML-Seite hat zeilen wie


Code:
<td class="irgendeineklasse"> <a  href="/irgendeinedatei.php/id=123456789">Irgend ein Text mit evtl. auch Zahlen und Sonderzeichen</a></td>


So, nun möchte ich einmal die ID abgreifen, und einmal natürlich den Text selbst.
Nach einem Tutorial habe ich mir das hier zusammen geschrieben...
Code:
Dim getid As New Regex("<td class=""irgendeineklasse""> <a  href=""/irgendeinedatei.php/id=.*"">.*</a></td>")
        Dim idmatches As MatchCollection = getid.Matches(rssourcecode)
        For Each id As Match In idmatches
            ListBox1.Items.Add(id.Value.Split("""").GetValue(3))
        Next

durch GetValue(3) bekomme ich id's inkl dessen vorzeichen /irgendeinedatei.php/id=
da ich ja durch "" teile...

Wie könnte man das sonst realisieren? :S
 
Günstig wäre, einen größeren Abschnitt der Datei zu kennen.

Dann mußt Du definieren, wann eine id für dich relevant ist. Du mußt also in mehreren Schritten vorgehen, um mit Sicherheit immer die Treffer zu bekommen, die Du wünscht.

Beispiel:
1. Anfangs-Tag finden (<td class =, eventuell noch href und id)
2. ID Position suchen und Wert lesen
3. nachfolgenden Text lesen

Eventuell geht der tag über mehere Zeilen, dann wird kompliziert.

Split hilft da of nicht weiter. Ist das eine einmalige Sache oder brauchst Du das mit vielen unterschiedlichen Dateien (html Seiten)?
 
erstmal danke für die antwort.

die datei hat einfach eine tabelle, und die css-klasse wiederholt sich im jeweiligen immer wieder, hier wollte ich einsteigen und das als anhaltspunkt nutzen.

hmm, naja da sollen schon mehrere seiten gelesen werden, das stellt aber glaube ich kein problem dar, da man das ja dann umbauen kann..

die id's und texte sind immer relevant, die sollen immer rausgezogen werden, denn sowohl die css klasse als auch die list.php ist n anhaltspunkt...


ich bekomme z.B. sowas raus:
/irgendeinedatei.php/id=123456789
/irgendeinedatei.php/id=156414861
/irgendeinedatei.php/id=68464945

oder wenn ich eben an anderer stelle ansetze
>Irgend ein Text mit evtl. auch Zahlen und Sonderzeichen</a></td>

ich möcht einfach nur den html kram weg haben.. ich denke eben, dass in diesem fall Split mit "" ungünstig gewählt wurde, denn in dem beispiel was ich gesehen habe konnte man mit dem split direkt alles sorgfältig abgreifen ohne html rückstände...
die id's wollte ich eben als integerwerte in ne tabelle eintragen, und jeweils in die gleiche zeile auch den text..

wie soll man sowas denn sonst realisieren? ^^
ich merk schon, regex ist mächtig, aber irgendwie kompliziert..
 
Also, mit Visual Basic kenne ich mich nicht so aus, aber ich denke, die regulären Ausdrücke sollten funktionieren:
Also, die ID könntest Du mit folgendem Ausdruck lesen (steht dann in der ersten Ergebnisgruppe, also Match):
(?<=id=)\s*(.+?)(?=")

Eventuell muß man id noch eindeutiger definieren (also ./php davor) sonst bekommst Du irrelevante Treffer (aber erst im nächsten Schritt)
 
Zuletzt bearbeitet:
die regulären ausdrücke sind wie ich gesehen habe in allen sprachen gleich, zumindest die befehlsteile.. wie man die dann anwendet ist ne andere sache ;) ich versuch mich ja durchzuringen, ob ich nicht doch lieber umsteige, aber vb fällt mir als anfänger etwas leichter, hatte vor einigen jahren viel mit php zutun, und das ist syntaxmäßig sehr ähnlich find ich..

die liste der ids die ich da raus bekomme, ist komisch.. :)

das muss ich auf jeden fall genauer definieren, sonst kommen da ungewollte dinge raus.. wie zb 4stellige id's obwohl die ids die ich brauche 7-9stellen lang sind ;)

ich komm damit nicht klar.. einerseits muss ich das anständig mit Regex("") filtern, und dann noch splitten, und sehr viel gibts leider nicht zu finden im netz, was genau sowas behandelt...


edit: ich wollts nur ungern nochmals hinterher durchfiltern, um diesen kram weg zu kriegen, denn so wie ich das verstanden habe ist RegEx genau dafür geeignet, um explizit dinge zu filtern..

Code:
Dim getjobid As New Regex("<a  href=""/list.php/id=\b[^>]*>(.*?)</a>")

funktioniert, genauso wie meine vorherigen versuche.
aber ich bekomme immer wieder folgendes raus:
/list.php/id=123456 und ähnliche strings.

ListBox1.Items.Add(id.Value.Split("""").GetValue(1))

ich verstehs nicht :D
 
Zuletzt bearbeitet:
Okay, wenn das mit den ID's so funktioniert (war ein kleiner Test, wegen den Lookarounds, die funktionieren nicht überall), dann ist das Vorgehen folgendes:

Erst den kompletten Tag lesen, der relevant ist und diesen dann untersuchen.

Alle relevanten Tags-Inhalte (zwischen den <a>...</a>:
(?<=<a).+?(?=/a>)

in dem Ergebnis die ID wie oben:
(?<=id=)\s*(.+?)(?=")

und im gleichen Ergebnis den Text eventuell mit split oder:
(?<=>).+?(?="<)
 
versteh ich das nun richtig dass man das mehrfach durch regex ziehen muss, um das ergebnis zu erhalten?...

ich muss mir das wohl viel tiefer zu gemüte führen... wollte ich eigentlich vermeiden, da das thema so groß ist.. und ich hab doch erst angefangen mit vb ^^

ps: so auf anhieb kann ich damit leider nichts anfangen, aber danke, ich werds als referenz nutzen, und mich weiter durchlesen


edit:

eigentlich müsste man doch einfach nur bei den Rauten alles abgreifen... -> Regex("id=#"">#</a>")

nur alles was ich da versuche, bringt nichts... muss man das so umständlich machen? ^^
 
Zuletzt bearbeitet:
ein frage: wiso machst du das mit Split?
Split teilt den Text an den Stellen, die in der Regex stehen auf. Das heißt die Stelle selbst wird entfernt und ist im Ergebnis nicht mehr verfügbar.

Du willst doch ID und so aus dem Text extrahieren oder? schau doch mal in der MSDN bei Regex.Match:
http://msdn.microsoft.com/de-de/library/twcw2f1c.aspx#Y114

dort gibt es auch ein VB-Beispiel:
Code:
Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim text As String = "One car red car blue car"
      Dim pattern As String = "(\w+)\s+(car)"

      ' Instantiate the regular expression object.
      Dim r As Regex = new Regex(pattern, RegexOptions.IgnoreCase)

      ' Match the regular expression pattern against a text string.
      Dim m As Match = r.Match(text)
      Dim matchcount as Integer = 0
      Do While m.Success
         matchCount += 1
         Console.WriteLine("Match" & (matchCount))
         Dim i As Integer
         For i = 1 to 2
            Dim g as Group = m.Groups(i)
            Console.WriteLine("Group" & i & "='" & g.ToString() & "'")
            Dim cc As CaptureCollection = g.Captures
            Dim j As Integer 
            For j = 0 to cc.Count - 1
      	      Dim c As Capture = cc(j)
               Console.WriteLine("Capture" & j & "='" & c.ToString() _
                  & "', Position=" & c.Index)
            Next 
         Next 
         m = m.NextMatch()
      Loop
   End Sub
End Module
' This example displays the following output:
'       Match1
'       Group1='One'
'       Capture0='One', Position=0
'       Group2='car'
'       Capture0='car', Position=4
'       Match2
'       Group1='red'
'       Capture0='red', Position=8
'       Group2='car'
'       Capture0='car', Position=12
'       Match3
'       Group1='blue'
'       Capture0='blue', Position=16
'       Group2='car'
'       Capture0='car', Position=21
 
ich weiß, ist ganz schön umständlich wie ich das da probiert habe, das war mir bewusst. die tollen "tutorials" die ich gefunden hatte haben sich mit was ähnlichem beschäftigt.. danke für die antwort, das ist denke ich genau das womit ich mich beschäftigen muss um da weiter zu kommen.

ich hab seit letztens auch nicht weiter gemacht, und mich da ein bisschen durchgelesen, aber split schien mir wie gesagt auch irgendwie falsch am platze.

genau, ich möchte id aus dem "unterlink" sozusagen extrahieren, und genauso den text der zwischen > und <



Ne frage nebenbei: Ist es überhaupt angedacht ein "muster" zu definieren das besagt dass man nur die zahlen nach dem davorstehenden zeichen auslesen will? ich seh' das überall nur so, dass man entweder nach diesen zeichenketten suchen kann, oder aber nach den zahlen an sich...



Edit: Nach einiger einiger einiger zeit endlich kapiert, wie ich das am elegantesten löse :)

einfach codeabschnitt in eine zeile hauen, zeilenumbrüche im original-code nachsehen, und \n pro umbruch dazwischen schreiben... sollte sowieso klar sein..
überall da wo man den text raus löschen muss, da er immer verschieden ist, fügt man (.*) ein
bei zahlen hab ich (\d*) genommen, ist aber im prinzip egal.. einfach genauer definiert




beispielcode: (ich schreib das aus meiner sicht, wenn jemand an meiner stelle sowas nochmal brauchen sollte, also nicht böse sein wenn ich zu weit aushole oder unsinnige sachen erkläre ^^)
Code:
Dim searchpattern As String = "<td class=""centered"">(.*)</td>\n\n\n<td class=""title""> <a  href=""/test.php/id=(.*)"">(.*)</a></td>\n<td>(.*)</td>"
Dim gettest As New Regex(searchpattern, RegexOptions.IgnoreCase)
Dim testmatches As MatchCollection = gettest.Matches(streamer("http://webseite.de/blabliblub.php")
der streamer ist üblich einfach eine httpwebrequest funktion / streamreader der den quelltext liest


zum überprüfen ob überhaupt etwas gefunden wird, oder ob das pattern fehlerhaft ist:
Label1.Text = testmatches.Count
kommt hier 0 raus, ist was faul.

die jeweiligen stellen im pattern die in klammern stehen, sind quasi gruppen..
mit folgendem trage ich alles in eine ListView ein

Code:
For Each testmatch As Match In testmatches
            Dim SubItem As ListViewItem
            With ListView1.Items
                SubItem = .Add(testmatch.Groups(1).Value)
                SubItem.SubItems.Add(testmatch.Groups(2).Value)
                SubItem.SubItems.Add(testmatch.Groups(3).Value)
                SubItem.SubItems.Add(testmatch.Groups(4).Value)
                SubItem.SubItems.Add(testmatch.Groups(5).Value)
                SubItem.SubItems.Add(testmatch.Groups(6).Value)
            End With

        Next

ist das denn wirklich so elegant wie ich finde, oder bin ich auf dem holzweg? wäre sehr nett wenn da jemand ein statement abgeben würde..

ich finde, es ist sehr explizit gehalten da viel "beispielcode" mit in die pattern genommen wird... und ich erspar mir dadurch viel regex.. die jeweiligen sachen werden perfekt abgegriffen..

da gibts nur noch ein problem.. bei einem &nbsp; geht hinterher nichts mehr ^^
 
Zuletzt bearbeitet:
also am Elegantesten ist es, wenn du mit jeder Regex genau die Teile extrahierst, die du brauchst. Das ist der Sinn dieser Mechanik. Es ist nicht zweckmäßig sich einen Großen Teil des Suchtextes herauszunehmen um diesen dann manuell zu parsen.

Also:

dani4u schrieb:
Ne frage nebenbei: Ist es überhaupt angedacht ein "muster" zu definieren das besagt dass man nur die zahlen nach dem davorstehenden zeichen auslesen will? ich seh' das überall nur so, dass man entweder nach diesen zeichenketten suchen kann, oder aber nach den zahlen an sich...

Ja, das ist möglich und hier der Schlüssel zu Erfolg - du stellst die richtigen Fragen :)

Die Übersicht der Regex-Syntax für .NET findet sich hier: http://msdn.microsoft.com/en-us/library/az24scfc.aspx

Was du hier brauchst sind die "Grouping Constructs", gnauer gesagt die Zero-width positive lookahead assertion und Zero-width positive lookbehind assertion.

Zero-width positive lookahead assertion
Das ist ein Ausdruck, der auf den gesuchten Folgen muss, sonst gibt es keinen Match. Die Syntax ist (?= expression). Beispiel:
Die Regex "Test(?=verfahren)" such erstmal nur die Textpassage "Test". Wenn direkt hinter "Test" die Zeichen "verfahren" kommen gibt es einen Match, sonst nicht. Im Text "Die Testverfahrenslösung des Testverfahrens ist der Test an sich" ergibt 2 Matches. Die Matches stammen von "Testverfahrenslösung" und "Testverfahrens". Der Match ist allerdings bei beiden nur "Test". Das letzte Test ist kein Match, da hinter Test ein Leerzeichen steht und nicht die Zeichenfolge "verfahren".

Zero-width positive lookbehind assertion.
Dasselbe wie lookahead, nur das vor der expression gesucht wird. Die Syntax ist (?<= expression)
Die Regex "(?<=Erfrischungs)getränk" findet im Text "Das Erfrischungsgetränk des getränks wird getränkt im Trank". Liefert nur einen Match. Der kommt hier von "Erfrischungsgetränk", der Inhalt des Matches ist aber nur "getränk".
 
hmm ja, davon hab ich glaub ich auch gelesen, aber ich konnte mir bisher in meinem speziellen fall keinen reim drauf machen, wie ich das anstellen soll.. ich bin bis jetzt nur mal heil froh, endlich die lösung gefunden zu haben wie ich aus codefragmenten bestimmte teile heraushole, die meist dynamisch sind. vorher hatte ich wie oben beschrieben Split verwendet, aber im nachhinein war das ne ziemlich doofe idee, das tutorial zu nehmen ^^

Danke schonmal.
bei msdn bin ich sowieso die ganze zeit am nachschlagen ;)

in meinem fall musste ich das glaube ich so machen, sonst hätte ich nicht mit einem rutsch die verschiedenen infos in die listview eintragen können.. oder?

das mit dem grouping erschien mir eigentlich bisher als beste wahl... ich werd das auch so lassen solange ich den fehler da nicht behoben habe... hoffentlich hat regex im pattern keine begrenzung.. :/



edit: grrr.. ich sitze hier seit einer stunde, und wundere mich wieso ab einer gewissen stelle die \n\n nicht mehr greifen und das ganze unbrauchbar wird... IM QUELLCODE WAR EIN LEERZEICHEN. :D

ich stell das nun fertig, kopiere es und dann schau ich mir das an was du meinst was ich brauchen würde ^^

danke für die beispiele, sehr verständlich und hilfreich ^^
 
Zuletzt bearbeitet:

Ähnliche Themen

Antworten
10
Aufrufe
1.099
C
Antworten
16
Aufrufe
2.828
C
Antworten
3
Aufrufe
9.545
CloudStrife
C
Zurück
Oben