Jürgen Auer
Legendäres Mitglied
Ein kleines Rätsel zu Weihnachten, in den letzten Tagen in der praktischen Arbeit darüber gestolpert:
Man hat ein Dokument. Dieses enthält eine Html-Tabelle, links stehen Beschriftungen, rechts der Inhalt.
Der Inhalt soll extrahiert werden.
Grundidee: Man führt einen RegEx mit diversen Gruppen aus. Anschließend stehen die Ergebnisse in den Gruppen:
Start:
CODE _rE = New RegEx("(?is:""abcd"">(?'subId'.+?), (?'Hauptname'.+?)</td>" & _
".*?>Name</td>.*?<td.*?>(?'Name'.*?)</td>" & _
".*?>Strasse/Postf\.:</td>.*?<td.*?>(?'Strasse'.*?)</td>" & _
".*?>PLZ, Ort: </td>.*?<td.*?>(?'PLZ'.*?) (?'Ort'.*?)</td>" & _
".*?>Telefon: </td>.*?<td.*?>(?'Telefon'.*?)</td>" & _
".*?>Telefax: </td>.*?<td.*?>(?'Telefax'.*?)</td>" & _
".*?>E-Mail: </td>.*?<td.*?>(?'EMail'.*?)</td>" & _
".*?>Homepage: </td>.*?<td.*?><a href=""(?'Homepage'.*?)"".*?</td>)")
(?is:...) setzt die SingleLine-Option, damit der Punkt als Suchmuster auch Zeilenumbrüche findet.
Die Ausdrücke & _ am Zeilenende sind lediglich Stringverkettungen innerhalb von VB.NET, tun also inhaltlich nichts zur Sache. "abcd" ist im Quelldokument ein Attributwert eines Attributes, steht dort in Hochkommata, die müssen in VB.NET doppelt maskiert werden.
Ansonsten:
QUOTE ".*?>Name</td>.*?<td.*?>(?'Name'.*?)</td>" & _
Finde minimal beliebige Zeichen (.*?), dann schließende Spitzklammer, das Wort Name gefolgt von </td>, minimaler Zwischenraum, <td, dann folgen irgendwelche Attribute, dann eine schließende Spitzklammer. Das danach bis </td> packe in die Gruppe 'Name' usw.
Einerseits: Passt die Quelldatei zu dieser Definition, funktioniert alles - die Ausführungszeit ist vernachlässigbar.
Andererseits: Fügt man nach dem Text ein Leerzeichen (oder eines mehr als dasteht) ein
Alt:
CODE ".*?>Strasse/Postf\.:</td>.*?<td.*?>(?'Strasse'.*?)</td>" & _
Neu:
CODE ".*?>Strasse/Postf\.: </td>.*?<td.*?>(?'Strasse'.*?)</td>" & _
dann wird nichts gefunden. Das alleine wäre noch kein Problem. Das Problem liegt darin, daß das eingefügte Leerzeichen bei Name zu einer Laufzeit von 10 Sekunden, bei Strasse/Postf zu einer Laufzeit von 18 Sekunden führt - das terminiert also nicht mehr innerhalb einer realistischen Zeit. Je später die Nicht-Übereinstimmung, umso länger die Laufzeit. Tatsächlich kommen noch mindestens zehn Zeilen dazu, das Problem potenziert sich also.
Rätsel: Wie läßt sich das Problem - durch einen verbesserten RegEx - lösen?
Man hat ein Dokument. Dieses enthält eine Html-Tabelle, links stehen Beschriftungen, rechts der Inhalt.
Der Inhalt soll extrahiert werden.
Grundidee: Man führt einen RegEx mit diversen Gruppen aus. Anschließend stehen die Ergebnisse in den Gruppen:
Start:
CODE _rE = New RegEx("(?is:""abcd"">(?'subId'.+?), (?'Hauptname'.+?)</td>" & _
".*?>Name</td>.*?<td.*?>(?'Name'.*?)</td>" & _
".*?>Strasse/Postf\.:</td>.*?<td.*?>(?'Strasse'.*?)</td>" & _
".*?>PLZ, Ort: </td>.*?<td.*?>(?'PLZ'.*?) (?'Ort'.*?)</td>" & _
".*?>Telefon: </td>.*?<td.*?>(?'Telefon'.*?)</td>" & _
".*?>Telefax: </td>.*?<td.*?>(?'Telefax'.*?)</td>" & _
".*?>E-Mail: </td>.*?<td.*?>(?'EMail'.*?)</td>" & _
".*?>Homepage: </td>.*?<td.*?><a href=""(?'Homepage'.*?)"".*?</td>)")
(?is:...) setzt die SingleLine-Option, damit der Punkt als Suchmuster auch Zeilenumbrüche findet.
Die Ausdrücke & _ am Zeilenende sind lediglich Stringverkettungen innerhalb von VB.NET, tun also inhaltlich nichts zur Sache. "abcd" ist im Quelldokument ein Attributwert eines Attributes, steht dort in Hochkommata, die müssen in VB.NET doppelt maskiert werden.
Ansonsten:
QUOTE ".*?>Name</td>.*?<td.*?>(?'Name'.*?)</td>" & _
Finde minimal beliebige Zeichen (.*?), dann schließende Spitzklammer, das Wort Name gefolgt von </td>, minimaler Zwischenraum, <td, dann folgen irgendwelche Attribute, dann eine schließende Spitzklammer. Das danach bis </td> packe in die Gruppe 'Name' usw.
Einerseits: Passt die Quelldatei zu dieser Definition, funktioniert alles - die Ausführungszeit ist vernachlässigbar.
Andererseits: Fügt man nach dem Text ein Leerzeichen (oder eines mehr als dasteht) ein
Alt:
CODE ".*?>Strasse/Postf\.:</td>.*?<td.*?>(?'Strasse'.*?)</td>" & _
Neu:
CODE ".*?>Strasse/Postf\.: </td>.*?<td.*?>(?'Strasse'.*?)</td>" & _
dann wird nichts gefunden. Das alleine wäre noch kein Problem. Das Problem liegt darin, daß das eingefügte Leerzeichen bei Name zu einer Laufzeit von 10 Sekunden, bei Strasse/Postf zu einer Laufzeit von 18 Sekunden führt - das terminiert also nicht mehr innerhalb einer realistischen Zeit. Je später die Nicht-Übereinstimmung, umso länger die Laufzeit. Tatsächlich kommen noch mindestens zehn Zeilen dazu, das Problem potenziert sich also.
Rätsel: Wie läßt sich das Problem - durch einen verbesserten RegEx - lösen?