PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Brett vorm Kopf - RegExp/Reguläre Ausdrücke


Mr_Snakefinger
2011-04-06, 11:00:34
Hi zusammen,

folgendes Problem, bei dem ich gerade ein wenig ein Brett vor dem Kopf habe:

Ich lese aus einem Dokument zeilenweise bestimmte Zellenwerte als String aus, die beispielhaft wie folgt aussehen können:


foo.bar.germany.de

foo.bar.uk.co.com

Reserved for foo.bar.germany.de

unused

Was ich brauche - und wobei ich mir gerade einen ziemlichen Ast bei abbreche - ist ein regulärer Ausdruck, der mir (auf oben genanntes Beispiel gemappt) zurückliefert:

foo.bar.germany.de

foo.bar.uk.co.com

foo.bar.germany.de

Also angenommen, die foo.bar-Teile sind FQDNs -> Ich will aus dem String, der gegen die RegExp gematcht wird, genau diese FQDN extrahieren (ohne diese jetzt auf Gültigkeit zu validieren). Streng genommen bräuchte ich nur das "foo", aber das kann man noch in einem zweiten Schritt nachziehen, wenn es erforderlich ist.

Aber entweder ich hab nen ziemliches Brett vor dem Kopf oder es geht schlichtweg nicht, egal, was ich da als RegExp zusammenbastele, ich bekomme nie das gewünschte Ergebnis. Kann mri mal wer auf die Sprünge helfen?

universaL
2011-04-06, 13:02:43
mal schnell zusammengespielt mit rubular.com

^(\w+\..*\w+)|\w+.* (\w+\..*\w+)

Monger
2011-04-06, 13:26:06
Gibt natürlich wiedermal unzählige Lösungsvarianten.

So spontan würde ich schreiben:


\b\w+(?:\.\w+)+\b


\b ist ja ein Anchor für Wortende/anfang. So garantiert man, dass nicht noch irgendwas direkt vorne dran steht, d.h. Http://www.example.com würde hiermit NICHT gematcht!

Mr_Snakefinger
2011-04-06, 21:27:36
Ah cool, danke schonmal für die Hilfe. Hatte noch keine Gelegenheit, das zu testen, weil ich zwischenzeitlich mit was anderem beschäftigt war, aber sobald ich die Gelegenheit habe, mache ich. Thx!

Mr_Snakefinger
2011-08-17, 18:14:34
Muss meinen alten Thread nochmal ausgraben...

Andere Fragestellung, aber mal wieder Probleme, den passenden regulären Ausdruck zu finden (sofern überhaupt möglich)...

Der String, der zu matchen ist, sie vom Aufbau her wie folgt aus:

<module><name>Modul1</name><value>Wert1</value></module><module><name>Modul2</name><value>Wert2</value></module><module><name>Modul3</name><value>Wert3</value></module>

Was ich letztlich davon brauche ist die Kombination von "Modul2" und "Wert2" (also ich brauche wirklich beides).

Normalerweise würde ich jetzt sowas machen (Python):

searchObject = re.search('<name>(.*)</name><value>(.*)</value>', <Eingabestring (s.o.)>, re.M)

value1 = searchObject.group(1)
value2 = searchObject.group(2)

Funktioniert ansonsten auch, aber in diesem speziellen Fall eben nicht, weil es danach (nach den Gruppierungen) noch weitergeht bzw. davor auch noch was kommt.

searchObject.group(1) würde also in obigem Beispiel alles zurückgeben, was nach dem ersten <name> kommt (bis einschließlich Wert3).

Jetzt kann ich das natürlich wie folgt einschränken:

searchObject = re.search('<name>Name2</name><value>(.*)</value>', <Eingabestring (s.o.)>, re.M)

In dem Fall bleibt das Kernproblem aber bestehen, weil nämlich das searchObject.group(1) alles ab Wert2 zurückgibt (bis einschließlich Wert3).

Daher also die Fragen:

* Kann ich das Problem überhaupt mit einer RegEx in den Griff bekommen?
* Wie sollte/könnte/müsste entsprechende RegEx aussehen?

Ich bedanke mich schon einmal für jeden positiven Input...


***** EDIT *****
Tante Edit ergänzt: Der zu durchsuchende String ist tatsächlich ein zusammenhängender String aus einem geöffneten Textfile und nicht etwa auf mehrere Zeilen verteilt (pro Wertpaar eine Zeile bspw.).

ne0
2011-08-17, 18:21:06
das liegt an der greedyness des (.*) catches. Probier mal (.*?) jeweils bei beiden groups.

Trap
2011-08-17, 18:21:39
Das dürfte helfen:
*?, +?, ??
The '*', '+', and '?' qualifiers are all greedy; they match as much text as possible. Sometimes this behaviour isn’t desired; if the RE <.*> is matched against '<H1>title</H1>', it will match the entire string, and not just '<H1>'. Adding '?' after the qualifier makes it perform the match in non-greedy or minimal fashion; as few characters as possible will be matched. Using .*? in the previous expression will match only '<H1>'.

Edit: 33 Sekunden zu langsam :(

Mr_Snakefinger
2011-08-17, 18:44:45
Danke schonmal an Euch zwei...

Da ich heute keinen Zugriff mehr auf das System hab, werde ich das morgen Vormittag mal testen.

Gebe danach nochmal Rückmeldung hier.

Trap
2011-08-17, 18:50:57
Alternativ hat Python natürlich auch Bibliotheken zur XML-Verarbeitung, z.B. http://docs.python.org/library/xml.etree.elementtree.html

Mr_Snakefinger
2011-08-17, 19:09:44
Ich weiß, die müsste ich mir auch mal ansehen...

Ich hab's auch schonmal versucht, damit klar zu kommen, aber das File, aus dem ich den Kram auslese, hat irgendwelche Macken. Das wird dynamisch zur Laufzeit generiert und der Output ist denkbar schlecht: Da kommt vom Server, der das File generiert, nur eine einzige lange Zeile zurück, nicht so, wie man XMLs normalerweise so kennt.

Ich hab mal probiert, das Teil mit Hilfe der XML-Bibliotheken in ein anständig formatiertes Dokument umzuformen, aber da hagelt es einen Fehler nach dem anderen, weswegen ich das zunächst erstmal umschiffen möchte, weil die Zeit etwas drängt. Erstmal Quick&Dirty, damit Ergebnisse da sind - schön machen kann man immer noch...

Monger
2011-08-17, 19:14:40
Was natürlich XML ist, sollte auch mit passenden XML Funktionen bearbeitet werden. Es muss nicht jeder wieder einen neuen XML Parser erfinden.

Was den Lazy Operator angeht: der hat gerne mal seine Tücken. Zum einen ist er inperformant (weil er von hinten nach vorne auflösen muss um die kleinste mögliche Einheit zu finden), zum anderen ergibt das mischen von Lazy und Greedy manchmal sehr unerwartete Effekte...

Gerade was Klammerfunktionen ist folgende Konstruktion oftmals praktisch: "match mir jedes Zeichen was keine schließende Klammer ist, bis zu dem Punkt wo eine schließende Klammer kommt." Also:


\([^)]+\)

matcht alle Ausdrücke die mit runden Klammern umgeben sind.

Mr_Snakefinger
2011-08-17, 19:32:56
Was natürlich XML ist, sollte auch mit passenden XML Funktionen bearbeitet werden. Es muss nicht jeder wieder einen neuen XML Parser erfinden.

Letzteres hab' ich auch nicht wirklich vor. ;)

Aber nicht alles, was nach XML aussieht oder die passende Datei-Endung trägt ist auch wirklich XML. Vermutlich habe ich die Funktionen, die ich getestet habe auch nicht korrekt genutzt, aber genau für das Suchen und Testen der richtigen Funktionen und deren Einstz fehlt gerade die Zeit.
Und da ich auch nicht alles aus dem File (eigentlich sind es mehrere, aber das Problem ist bei allen das gleiche) benötige, sah es anfangs einfacher aus, den kompletten String (und es ist nur eine ewig lange Zeichenkette, die da generiert wird) nach bestimmten Sachen zu RegExen, um kurzfristig ein passendes Ergebnis zur Hand zur haben.

Das das weder schön noch höchst-performant ist, ist aktuell erstmal nebensächlich. Dafür ist später noch Zeit.

Gast
2011-08-18, 08:34:42
Das Provisorium hält am längsten. ;)

Mr_Snakefinger
2011-08-18, 09:00:30
das liegt an der greedyness des (.*) catches. Probier mal (.*?) jeweils bei beiden groups.

Der tut! Danke! :)

Zumindest für den aktuellen Fall, mal sehen, wann ich wieder Hilfe brauche... ;)


Das Provisorium hält am längsten. ;)

Häufig ist das so, kann ich bestätigen.
In dem konkreten Fall sieht der Code aber sehr sehr "provisorisch" aus, da muss auf jeden Fall nochmal poliert werden...

Mr_Snakefinger
2013-10-29, 11:07:22
Ach verdammt... Ab und an kommt es doch mal vor, dass ich irgendwas zusammen coden muss...

Da ich etwas Ähnliches schonmal hatte, krame ich den Krempel mal raus...

Folgendes bekomme ich von einem URL-Aufruf aus einem Skript zurück:


<head>
<title>Network Switch Data</title>
</head>
<meta content=no-cache">
<body>
Zeile 1 (diverses Zeugs, durch Komma getrennt)
Zeile 2 (diverses Zeugs, durch Komma getrennt)
Zeile 3 (diverses Zeugs, durch Komma getrennt)
Zeile 4 (diverses Zeugs, durch Komma getrennt)
Zeile 5 (diverses Zeugs, durch Komma getrennt)
</body>
</html>


Interessant ist dabei nur das, bas in den Body-Tags steht. Da komme ich auch ganz gut ran, wenn ich Folgendes mache:

re.findall('(?<=<body>)([\s\S]*)(?=<\/body>)', URL_DATA)

Allerdings gibt mir das die Zeilen als einen langen String zurück, sprich das Ergebnis sieht dann irgendwie so aus:

Zeile1\nZeile2\nZeile3 usw.

Ich breche mir hier gerade einen ab, um das \n, also den Zeilenumbruch noch irgendwie mit in den Ausdruck zu bekommen, so dass mir das findall die einzelnen Zeilen matcht, aber irgendwie will das nicht.

Vermutlich ist es nur eine Kleinigkeit, aber ich komm nicht drauf. Eventuell kann mir mal jemand auf die Sprünge helfen?

Monger
2013-10-29, 12:25:11
Manche Programmiersprachen haben in ihren Regex Funktionen extra Optionen um Zeilenumbrüche zu behandeln. In .NET sieht das z.B. so aus:

var matches = Regex.Matches("\d+", "1234ab\n12434", RegexOptions.MultiLine);

Mr_Snakefinger
2013-10-29, 14:40:54
Ich hab schon versucht, das "\n" mit in den Ausdruck zu packen, das hat allerdings nicht wirklich geholfen. Aber das Multiline hab ich bisher nicht auf der Tapete gehabt.

Danke für den Tipp, ich werde das später nochmal probieren. Für den Moment mache ich den Split quasi händisch, aber das sollte nicht dauerhaft so bleiben.