Laden...

Grundsätzliche Fragen zu Regex

Erstellt von Fabian vor 19 Jahren Letzter Beitrag vor 19 Jahren 9.215 Views
Fabian Themenstarter:in
1.985 Beiträge seit 2004
vor 19 Jahren
Grundsätzliche Fragen zu Regex

Nabend,

ich habe ein paar grundsätzliche Fragen zu Regex. Es geht mir um Informationen, wozu man sie normalerweise verwendet und was die Vorteile gegenüber der "primitiven" Suche nach Substrings ist.

Informationen zu den Punkten :

  • Metazeichen
  • Quantifizierer
  • Stichwort Greediness

wären auch sehr sehr hilfreich.

Danke und Gruß,
Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo Fabian,

ein bisschen habe ich ja schon hier geschrieben:

http://mycsharp.de/wbb2/thread.php?threadid=4311#post17782

Ansonsten ist der Hauptvorteil die größere Flexibilität, insbesondere, wenn man ein Eingabedaten hat, wo die einzelnen Bestandteile unterschiedliche Längen haben und Datenfelder optional sein können. Den größten Nutzen hat man, wenn man Informationen extrahieren oder aufbereiten will, z.B. alle URLs aus einer HTML-Datei heraussuchen oder ein Doku-Format in anderes überführen.

Außerdem, wenn man RexEx einmal gelernt hat, nicht nur in nicht nur in C# benutzen, sondern z.B. auch in anderen Programmiersprachen, in Editoren, als Parameter von (UNIX-)Kommandos.

Metazeichen sind z.b. sowas wie
. was für ein beliebiges Zeichen steht
\d was für eine Ziffer steht
\s was für ein White Space steht (Leerzeichen, Tab, Newline)

Quantifizierter geben an, wie oft ein Zeichen oder eine Zeichenfolge wiederholt wird

  • bedeutet beliebig oft, mindestens einmal
    * bedeutet beliegig oft, einschließlich null-mal
    {n,m} mindestens n-mal, höchstens m-mal

Greedy, also gierig, bedeutet, dass bei der Verwendung von Quantifizieren, der RegEx-Algorithmus immer versucht, die längstmögliche Wiederholung zu benutzen. Also, wenn drei Ziffern hintereinander stehen, dann werden für \d+ auch die drei Ziffern verwendet und nicht etwa nur zwei.

Wenn Du mehr wissen willst, frag einfach.

HTH

herbivore

P
939 Beiträge seit 2003
vor 19 Jahren

Beispiel Zeitangaben parsen:

"(\d{2}):(\d{2}):(\d{2})" ist ein regulärer Ausdruck, der dreimal die Gruppe "(\d{2})" getrennt durch ":"-Zeichen enthält. Eine Gruppe ist ein Teilergebnis, das später aus dem Gesamtergebnis abgefragt werden kann. In diesem Fall sind das die Stunden, Minuten und Sekunden. Gruppen werden durch runde Klammern angegeben. Bis auf das ":"-Zeichen, dass direkt ins Ergebnis übernommen wird, enthält der Ausdruck nur Metazeichen. "\d{2}" bedeutet "genau zwei Ziffern".

In C# kann mit diesem Ausdruck ein Text nach Zeitangaben durchforstet werden.

string text = "Beim nächsten Ton ist es 22:33:00.";

string timePattern = @"(\\d{2}):(\\d{2}):(\\d{2})";
Regex timeParser = new Regex(timePattern, RegexOptions.Compiled);

foreach(Match m in timeParser.Matches(text)) {
  string timeString = m.Groups[0];    // "22:33:00"
  string hourString = m.Groups[1];    // "22"
  string minuteString = m.Groups[2];  // "33"
  string secondString = m.Groups[3];  // "00"
}

Der Ausdruck ist für das Beispiel ein bisschen vereinfacht worden. Er findet nicht "5:00:00", dafür aber "25:80:00".
Eine gute Quelle für präzisere, reguläre Ausdrücke ist: www.regxlib.com.
Ein Tool zum Testen von .Net Regexes ist Expresso http://www.codeproject.com/dotnet/expresso.asp.

Gruss
Pulpapex

333 Beiträge seit 2004
vor 19 Jahren

Regex g
|
|
|
v

([bb]|[^b]{2})

P
939 Beiträge seit 2003
vor 19 Jahren

"b" or not to "b"?

("[bb]" ist aber Unsinn. Und warum "{2}"?)

// Edit: jetzt habe ich es, "2 b or not 2 b": **{2}|[^b]{2}

Fabian Themenstarter:in
1.985 Beiträge seit 2004
vor 19 Jahren

Nabend,

danke schon mal für Eure Antworten. Damit kann ich schon mal ne Menge anfangen. Über das Thema soll ich am Mittwoch einen kleinen Vortrag (15-20 Min) halten. Mal sehen ob ich das hinbekomme 🙂.

Gruß,
Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de

333 Beiträge seit 2004
vor 19 Jahren

Original von Pulpapex
"b" or not to "b"?

("[bb]" ist aber Unsinn. Und warum "{2}"?)

"To be or not to be" eben. Jups, das mit dem "[bb]" is net ganz korrekt und "{2}" heißt eben in dem Fall auch nur two/to. Habs so ausm original, wahrscheinlich isses so ums ein bissel schwieriger zu machen 😉

Edit: Jo 🙂

([bb]|[^b]{2})

C
980 Beiträge seit 2003
vor 19 Jahren

Obwohl man mit regulären Ausdrücken viel parsen kann sind sie natürlich auf reguläre Grammatiken beschränkt. Bei irregulären Sprachen wie "zuerst einige 'x' danach einige 'y' aber gleichviele 'x' wie 'y'" kann man mit regulären Ausdrücke entsprechend nichts anfangen (wie der Name schon sagt) ... auch Programmcode kann man damit nicht parsen oder verifizieren (!)

V
842 Beiträge seit 2003
vor 19 Jahren

Doch man kann die Kommentare eines Quellcodes parsen, sehr praktisch um diese zu entfernen oder einfach zu extrahieren. Strings im Quellcode kann man damit auch noch erkennen. Hätte man für nen Parser schonmal die halbe Miete. g

P
939 Beiträge seit 2003
vor 19 Jahren

Es geht nicht um einzelne Ausdrücke, sondern um ganze Programme. Ein regulärer Ausdruck kann keine "Sätze" einer Sprache verifizieren, die beliebig tief geschachtelte Blöcke erlaubt.

V
842 Beiträge seit 2003
vor 19 Jahren

Meinst du jetzt Blöcke ({/Code/}) oder ineinander verschachtelte Strings ("bla"blubb"bla")?
Achja, ich wollte noch ein Buch empfehlen an den Threadstarter in dem Reguläre Ausdrücke sehr schön gezeigt und erkärt werden, auch mit dem .NET-Framework:
Reguläre Ausdrücke

Vellas

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo zusammen,

es ist schon richtig, dass "Ein regulärer Ausdruck [...] keine 'Sätze' einer Sprache verifizieren [kann], die beliebig tief geschachtelte Blöcke erlaubt.", aber natürlich kann man ein C# Programm schreiben, dass dies unter Verwendung von RE tut. Das was RE nicht leisten (können), muss in die restliche Programmlogik gesteckt werden.

herbivore

Fabian Themenstarter:in
1.985 Beiträge seit 2004
vor 19 Jahren

Hallo Vellas,

danke für die Buchempfehlung. Die Einleitung und die Kommentare lesen sich schon mal sehr gut. Ich halte von O'Reilly auch generell sehr viel. Das Buch kommt auf meine Wunschliste 🙂.

Danke und Gruß,
Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de

V
842 Beiträge seit 2003
vor 19 Jahren

Ja, ich habe auch an "normale" Strings gedacht, nicht an verschatelte.
In Programmcode kann man aber teile (einzelne Ausdrücke) parsen. Also Schlüsselwörter sollten eigentlich nicht so das Problem sein. Immerhin muss man diese nur suchen und darauf achten das vor oder hinter einem Schlüsselwort nur bestimmte Zeichen stehen dürfen, damit es gehighlighted wird. Das damit nicht die Korrektheit der Syntax geprüft werden kann ist wohl klar.

@Fabian:
Ja, habe zar nur 2 oder 3 Bücher davon, aber die Bücher die ich von O'Reilly habe sind wirklich sehr gut.

333 Beiträge seit 2004
vor 19 Jahren

Wie funktioniert denn so ein Parser der rein auf Regex basiert? Ich mein, ich kenne Spart, was ja so ein Ansatz ist, aber wie funktioniert sowas wenn man direkt über Regex arbeitet? Kennt da jemand Beispiele?

BTW: Schönes Tool zum testen und experimentieren mir .NET-Regex ist übrigens Expresso.

([bb]|[^b]{2})

V
842 Beiträge seit 2003
vor 19 Jahren

@NoOneKnows:
Ich bin von einem Internetparser ausgegangen. Dabei wäre es einfach durch suchen und ersetzen zu realsisieren, da dort nur entsprechender Code eingefügt werden muss der einen Textteil farbig hervorhebt.
In einem richtigen Parser könnte man aber Reguläre Ausdrücke zum parsen der Token sehr gut verwenden. Dazu findet man mit ein wenig suchen aber auch was bei google, habe leider kein Beispiel mehr, zumindest kein verfügbares, hatte da nämlich mal was bei google gefunden.

C
980 Beiträge seit 2003
vor 19 Jahren

Ich hatte bei einem meiner grösseren Parser auch mal mit regulären Ausdrücken gearbeitet, mit der ich mir einfach den string in einen tokenstream vorbereitet hatte ... die Regex übernahm somit also die Rolle des Lexers - war machbar wegen einfacher Grammatik. Für mehr kannst eine Regex in einem allgemeinen Parser imo nicht brauchen ... btw, den Regex Teil hab ich mittlerweise rausgeschmissen und mit nem eigenen echten (streambaren) Lexer ersetzt ...

Spart hat übrigens wenig mit regulären ausdrücken zu tun (ausser dass man damit natürlich auch reguläre Ausdrücke formulieren kann - aber Spart müsste mit jeder kontextfreien Sprache zurecht kommen ..?)

Fabian Themenstarter:in
1.985 Beiträge seit 2004
vor 19 Jahren

Nabend,

ich habe doch noch eine Frage:

Was bewirkt der Quantifizierer "?". Ich habe ihn in Verbindung mit <...> gesehen:


Regex r = new Regex("^(?<name>\\w+):(?<value>\\w+)");
Match m = r.Match("Section1:119900");

Als Laie würde ich sagen, dass man damit einen Alias vergeben kann, weil ich bei dem obigen Beispiel mit m.Groups["name"] drauf zugreifen kann. Stimmt das? Kann man damit einen Alias für eine Gruppe angeben?

Hat jemand vielleicht eine Übersicht über die gebräuchlisten Metazeichen und Quantifizierer? Dann kann ich mir für meinen Vortrag ein paar raussuchen und erklären 🙂.

Danke und Gruß,
Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de

P
939 Beiträge seit 2003
vor 19 Jahren

Du hast Recht. In .Net Regexes kann man mit "(?<name>...)" eine Gruppe benennen. Normalerweise ist das Fragezeichen jedoch der Quantifizierer für 0 oder 1 Wiederholungen. Dann steht es hinter einem Ausdruck.

Die .Net Regex-Syntax wird in der Msdn-Hilfe beschrieben: Link

Als Einstieg reichen die Punkte: Character Classes, Quantifiers, Grouping Constructs und Alternations und vielleicht "Atomic Zero-Width Assertions".

Fabian Themenstarter:in
1.985 Beiträge seit 2004
vor 19 Jahren

Hallo Pulpapex,

danke für den Link und die Erklärung. Das hilft mir schon mal sehr weiter. Jetzt habe ich aber eine Frage zu "\p{name}". Kannst Du mir erklären, was das bedeutet? Aus der englischen Erklärung bin ich nicht ganz schlau geworden.

Gibt es die MSDN-Hilfe evtl. auch auf Deutsch? Normalerweise bevorzuge ich ja die Englische, da es in der deutschen Übersetzung Fehler geben kann. Aber gerade bei etwas schwierigeren englischen Erklärungen, wo ich nicht weiterkomme, schaue ich doch gerne mal in die deutsche, um weiter zu kommen.

Gruß,
Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de

V
842 Beiträge seit 2003
vor 19 Jahren

\p und \P sind für Unicode-Eigenschaften und -Blockbereiche. Dies benötigst du bei der Suche nach Zeichenklassen. Z.B. bedeutet \d eine Ziffer und entspricht [0-9]. So gilt \p bei Unicode. Was in die geschweiften Klammern kann musst du der MSDN entnehmen. Ich würde dir echt raten dir für deinen Vortrag das Buch "Reguläre Ausdrücke" zu holen. Dort ist auch das alles sehr ausführlich erklärt und es wird auch auf die RegEx-.NET eingegangen, wie auch auf die von Java.

Vellas

Fabian Themenstarter:in
1.985 Beiträge seit 2004
vor 19 Jahren

Hallo Vellas,

danke für die Erklärung. Das Buch werde ich mehr sehr wahrscheinlich kaufen. Problem daran ist nur, dass der Vortrag morgen ist und ich es bis dahin nicht mehr bekomme 🙂. Ist in diesem Fall aber auch nicht so tragisch, da es ein kleiner 15 Minuten Vortrag ist und ich auch nur die grundlegensten Sachen erklären soll. Die Infos, die ich jetzt habe, reichen also schon vollkommen aus.

Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de

333 Beiträge seit 2004
vor 19 Jahren

@ Verllas und cdr:
Danke für die Antworten. Das man relativ leicht über regüläre Ausdruck zum Beispiele eine Art Syntax-Highlighting realisieren kann ist schon klar. Worum es mir geht ist eben die Korrektheit einer Syntax zu überprüfen. Sowas konnte man ja mit Spart machen, denk ich. Dort bassierte also ein ein Typ "Operator" zum Beispiel auf Arithmetischen, Logisch, Relationalen Operatoren, die Typen für sich waren. Und die "Arithmetischen Operatoren" sind dann wieder Typen, eben in diesem Fall + - / * usw. So konnte man zum Beispiel wieder definieren wie sich ein "Ausdruck" zusammensetzt, nämlich z.B. über Operand Operator Operand. Und sowas würd ich halt gern rein basierend auf reguläre Ausdrücke mache. Im endeffekt sowas was auch der Resharper macht, nämlich OnTheFly die Syntax auf ihre korrektheit prüfen, nur das ganze wollte ich nicht für C#, sondern für SQL-Anweisungen und da stecken ja auch sehr viel syntaktische Muster drin. Nur ich hab irgendwie keinen Ansatz wie man an sowas über Regex rangeht!? Oder sollte man da eh einen anderen Weg gehen?

([bb]|[^b]{2})

C
980 Beiträge seit 2003
vor 19 Jahren

Die Syntax wirst du nicht mit einer Regex alleine überprüfen können. Mit Spart geht das, weil Spart mit allen kontextfreien Sprachen umgehen kann (jede mir bekannte Programmiersprache ist kontextfrei) ... jede reguläre Sprache ist kontextfrei (darum kannst du mit Spart reguläre Ausdrücke parsen), aber nicht umgekehrt. Jede Sprache die irgendwelche Rekursionen zulässt ist nicht regulär. Deine Operatorendefinitionen sind aber rekursiv definiert sobald sowas wie Klammern zulässt. Nur schon das Überprüfen ob gleichviele öffnende wie schliessende Klammern vorkommen sind ist nicht regulär (und mit einem regulären Ausdruck nicht möglich), denn dafür würdest du einen Zähler brauchen (in regulären Ausdrücken gibt es keine Zähler) ...

Natürlich kannst du die Regex wie oben erwähnt als Lexer verwenden - hast du diesen Ansatz gemeint? (falls ja vergiss den absatz oben...)

P
939 Beiträge seit 2003
vor 19 Jahren

Guck dir mal ANTLR an. Das ist ein ausgereifter Compiler Compiler mit APIs für Java, C++ und C#. ANTLR wird z.B. für den HQL-Parser von Hibernate (O/R Mapper) eingesetzt. HQL ist SQL sehr ähnlich, wurde aber um einige OO-Ansätze erweitert.

333 Beiträge seit 2004
vor 19 Jahren

Okay, danke. Also kommt es nicht in Frage so etwas über reguläre Ausrücke zu machen. Hab mal einen kleinen Blick auf ANTLR geworfen und war erstmal etwas überfordert, weil mir die Funktnionsweise noch nicht ganz klar, also was das Ding macht 😉 Ich hab mir Beispiel Grammatik-Dateien angeschaut, womit man ja scheinbar solche syntaktischen Gegebenheiten definieren kann. Das sieht schonmal nicht schlecht aus. Was ich brauch ist dann so ein fefrtiger Parser für SQL, den ich direkt über .NET/C# ansprechen kann und der mir meine eingegebene SQL Statements überprüft und zurückgibt, wo die Syntax inkorrekt ist und weshalb dies der Fall ist.

([bb]|[^b]{2})

P
939 Beiträge seit 2003
vor 19 Jahren

So ein Parser wird dir von ANTLR aus einer Grammatik-Datei generiert. Fang am besten mit einer einfachen Grammatik an. Sagen wir zwei Zahlen addieren: <zahl> + <zahl>. Wenn du die Grundlagen drauf hast, kannst du dir ja die Grammatik von HQL anschauen. Die müsste hoffentlich im Hibernate 3 Packet dabei sein. Immerhin ist es ein Open Source Projekt.

HQL ist im grossen und ganzen identisch mit SQL. Es gibt nur einige Erweiterungen. Z.B. Anfragen über Objekt-Eigenschaften, in SQL ein Join über mehrere Tabellen.

Beispiel: Bestellungen bei Lieferanten aus dem selben Ort selektieren.

select b
from Bestellung b
where b.lieferant.adresse.ort = 'Xyz';

Oder: Bestellungen mit einem bestimmten Artikel selektieren.

select b
from Bestellung b
inner join b.positionen p
where p.artikel.name = 'Abc';
Fabian Themenstarter:in
1.985 Beiträge seit 2004
vor 19 Jahren

Hallo,

nach einer kleinen Verzögerung hatte ich diese Woche Mittwoch meinen Vortrag 🙂. Ich wollte mich bei allen bedanken, die mir in diesem Thread auf die Sprünge geholfen haben (war ja mein erstes wirkliches Zusammentreffen mit RegEx). Ich bin echt auf den Geschmack gekommen und werde mir das von Vellas empfohlene Buch zulegen.

Gruß,
Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de