RegExp-Kurs 06: Punkt, Quantoren

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Huo
Beiträge: 783
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Huo » 30.05.2022 10:20:31

tegula hat geschrieben: ↑ zum Beitrag ↑
29.05.2022 12:43:52
Meillo hat geschrieben: ↑ zum Beitrag ↑
28.05.2022 19:58:17
(Und im Ernst: Gerade ist's fuer mich schwierig mal eine laengere Zeit fuer konzentrierte Arbeit zu finden. Das RL ist gerade vollgestopft. Ich fuerchte, dass ich den naechsten Teil wohl erst am Montag veroeffentlichen koennen werde. Aber er wird kommen, keine Sorge.)
Danke! Cool, dass du trotzdem den Kurs weitermachst :THX:
tegulas Worten möchte ich mich vollumfänglich anschließen. Vielen Dank, Meillo, für den tollen RegExp-Kurs! Letzten Endes hast Du Dir damit mehr Arbeit aufgehalst als uns Teilnehmern. :THX:

Nochmal zu Aufgabe 10: Da ich, was die Komplexität der Aufgabeninterpretation betrifft, nicht hinter tegula und inne zurückstehen wollte :wink: , habe ich jetzt meine Lösung so erweitert, dass
(1) Keine Beträge unter 1.000 Euro gematcht werden,
(2) optionale zweistellige Cent-Beträge gematcht werden,
(3) eine optionale Währungsangabe (EUR, Euro oder €) gematcht wird,
(4) eine vordere Wortgrenze mit \< gesetzt wird (angeregt durch tegula, auch wenn wir's noch nicht durchgenommen haben),
(5) beliebig viele führende Nullen kein Problem darstellen, allerdings mit gematcht werden.

Code: Alles auswählen

\<0*[1-9][0-9]{0,2}(\.[0-9]{3})+(,[0-9]{2})?([[:blank:]](EUR|€|Euro))?

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von inne » 30.05.2022 10:41:15

Was heisst schon hinterherstehen, imo haben wir alle noch keine schöne Lösung :-)

Auch hier ist eine Fehlerhafte Eingabe (Tippfehler z.B.) gleich ein False-Positiv in der Ausgabe und Text wie 100.0000.000.000,00 EUR wird fast schon undefiniert gehandhabt?

Huo
Beiträge: 783
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Huo » 30.05.2022 10:56:21

inne hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 10:41:15
Auch hier ist eine Fehlerhafte Eingabe (Tippfehler z.B.) gleich ein False-Positiv in der Ausgabe und Text wie 100.0000.000.000,00 EUR wird fast schon undefiniert gehandhabt?
Dein Beispiel wird von meiner RE nicht gematcht:

Code: Alles auswählen

$ echo "100.0000.000.000,00 EUR" | egrep -o '\<0*[1-9][0-9]{0,2}(\.[0-9]{3})+(,[0-9]{2})?\>([[:blank:]](EUR|€|Euro))?'
$
Aber man braucht nur Deine "vertippten" vier Nullen hinter den zweiten Punkt zu setzen, um tatsächlich eine nicht-intendierte Ausgabe zu erhalten:

Code: Alles auswählen

$ echo "100.000.0000.000,00 EUR" | egrep -o '\<0*[1-9][0-9]{0,2}(\.[0-9]{3})+(,[0-9]{2})?\>([[:blank:]](EUR|€|Euro))?'
100.000
Ich bin offen für Vorschläge, eine solche Ausgabe zu verhindern – oder aber eine Toleranz für Tippfehler einzubauen. :mrgreen:

inne
Beiträge: 3289
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von inne » 30.05.2022 12:05:28

Huo hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 10:56:21
Aber man braucht nur Deine "vertippten" vier Nullen hinter den zweiten Punkt zu setzen,
Hier bekomme ich aber auch mit vier Nullen schon nach dem ersten Punkt etwas falsches:

Code: Alles auswählen

$ echo 100.0000.000.000,00 EUR | egrep -o '\<0*[1-9][0-9]{0,2}(\.[0-9]{3})+(,[0-9]{2})?([[:blank:]](EUR|€|Euro))?'
100.000

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Meillo » 30.05.2022 12:35:28

Das sind ja alles valide Matches ... nichts an euren REs gibt an, dass das Gematchte ein vollstaendiges Wort sein muss! Es wuerde auch den Zahlwert in ``aaaa1.234bbbb'' matchen.

Wenn man vorne und hinten beispielsweise auf Whitespace oder aehnliches abgrenzen moechte, dann geht das mit Lookaheads und Lookbehinds (die schauen was da kommt, ohne es in den Treffer einzubeziehen). Die gibt es aber in EREs nicht. Dafuer muss man PCREs verwenden.


Eine wichtige Erkenntnis ist wohl, dass sich REs sehr gut eignen, um schnell flexibel zu matchen, aber dass es schnell kompliziert wird wenn man versucht perfekte Loesungen zu schaffen. Irgendwo kippt die Kosten-Nutzen-Rechnung. Die Aufgaben hier sind ja zumeist abstrakt, darum ist es schwer, einen guten Kompromiss zu finden. Bei vielen Anwendungen in der Praxis kann man es sich deutlich einfacher machen (z.B. beim Datum mit `[0-9][0-9]' matchen, obwohl es den 99. Tag im Monat nicht gibt).

Es ist eine gute Uebung, eine RE mal schrittweise auszubauen, wie ihr das mit den Tausendertrennern gemacht habt. Wenn man sie selber aufgebaut hat, ist sie meist noch ganz gut verstaendlich. Wenn jemand anderes draufschaut, dann sieht es zu Beginn zunaechst nur wie Zeichensalat aus. Auch diese Leseuebung ist wertvoll. Ihr lernt dabei ein Gefuehl zu entwickeln, wo die Grenze der Lesbarkeit bei REs in etwa liegt.

Fuer manche Aufgaben sind sie perfekt geeignet, fuer andere nicht mehr so sehr. Man muss eben wissen wann und wie. Dazu braucht man eigene Erfahrung.
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Meillo » 30.05.2022 12:38:18

Huo hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 10:20:31
tegula hat geschrieben: ↑ zum Beitrag ↑
29.05.2022 12:43:52
Danke! Cool, dass du trotzdem den Kurs weitermachst :THX:
tegulas Worten möchte ich mich vollumfänglich anschließen. Vielen Dank, Meillo, für den tollen RegExp-Kurs! Letzten Endes hast Du Dir damit mehr Arbeit aufgehalst als uns Teilnehmern. :THX:
Dann waren die Aufgaben wohl nicht schwer genug. :-P ;-)

Es freut mich sehr, dass er euch gefaellt und etwas bringt.

Der letzte ERE-Teil ist nun online. Auf die Aufgaben und Loesungen hier werde ich noch eingehen.

Der Kurs ist damit aber noch nicht beendet, nur das ERE-Kapitel ist es. Weiter geht es mit Programmiersprachumsetzungen. Dazu mehr in einem separaten Post demnaechst ...
Use ed once in a while!

Huo
Beiträge: 783
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Huo » 30.05.2022 12:58:56

Meillo hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 12:35:28
Bei vielen Anwendungen in der Praxis kann man es sich deutlich einfacher machen (z.B. beim Datum mit `[0-9][0-9]' matchen, obwohl es den 99. Tag im Monat nicht gibt).
Ja, ich glaube auch, dass es in der Praxis bei der Frage, welche schrägen Ausnahmefälle es zu berücksichtigen gilt, auf den Zusammenhang ankommt. Will man z.B. Kontoauszüge durchsuchen, wird man davon ausgehen dürfen, dass keine wie von inne angesprochenen vertippten vier Ziffern zwischen Tausenderpunkten auftreten.
inne hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 12:05:28
Huo hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 10:56:21
Aber man braucht nur Deine "vertippten" vier Nullen hinter den zweiten Punkt zu setzen,
Hier bekomme ich aber auch mit vier Nullen schon nach dem ersten Punkt etwas falsches:

Code: Alles auswählen

$ echo 100.0000.000.000,00 EUR | egrep -o '\<0*[1-9][0-9]{0,2}(\.[0-9]{3})+(,[0-9]{2})?([[:blank:]](EUR|€|Euro))?'
100.000
Das wird daran liegen, dass Du den von echo übergebenen Eurobetrag anders als ich nicht in doppelte Quotes gesetzt hast. Ein Begründung dafür, warum das einen Unterschied macht, fällt mir allerdings gerade nicht ein.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Meillo » 30.05.2022 13:04:22

Huo hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 12:58:56
inne hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 12:05:28
Huo hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 10:56:21
Aber man braucht nur Deine "vertippten" vier Nullen hinter den zweiten Punkt zu setzen,
Hier bekomme ich aber auch mit vier Nullen schon nach dem ersten Punkt etwas falsches:

Code: Alles auswählen

$ echo 100.0000.000.000,00 EUR | egrep -o '\<0*[1-9][0-9]{0,2}(\.[0-9]{3})+(,[0-9]{2})?([[:blank:]](EUR|€|Euro))?'
100.000
Das wird daran liegen, dass Du den von echo übergebenen Eurobetrag anders als ich nicht in doppelte Quotes gesetzt hast. Ein Begründung dafür, warum das einen Unterschied macht, fällt mir allerdings gerade nicht ein.
Der Unterschied ist, dass ihr unterschiedliche REs verwendet. ;-)

Huo hat einen Wortendeanker (\>) nach den Zahlen, den inne nicht hat.


Ob mit oder ohne Anfuehrungsstriche macht in diesem Fall keinen Unterschied. Das kannst du ausprobieren wenn du die Ausgabe von `echo' z.B. nach `od -c' pipest und vergleichst.
Use ed once in a while!

Huo
Beiträge: 783
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Huo » 30.05.2022 13:14:36

Meillo hat geschrieben: ↑ zum Beitrag ↑
30.05.2022 13:04:22
Huo hat einen Wortendeanker (\>) nach den Zahlen, den inne nicht hat.
Ha, stimmt, den hatte ich beim Testen versuchsweise ausprobiert und vergessen wieder zu entfernen. Man muss bei solchen RE-Ungetümen wirklich sehr genau hinschauen. :lol:

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: RegExp-Kurs 06: Punkt, Quantoren

Beitrag von Meillo » 05.06.2022 09:39:15

Hierzu wollte ich noch was schreiben ...
Huo hat geschrieben: ↑ zum Beitrag ↑
25.05.2022 01:43:36
4) Schreibe die entsprechenden Intervallausdruecke fuer die drei anderen Quantoren: * + ?
* -> {0,} oder {,}
Die Form `{,}' ist unportabel, weder POSIX noch Henry Spencers regex-Lib beschreiben sie als erlaubt (auch wenn sie vielleicht trotzdem funktioniert).
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04_06 hat geschrieben: When an ERE matching a single character or an ERE enclosed in parentheses is followed by an interval expression of the format "{m}", "{m,}", or "{m,n}", together with that interval expression it shall match what repeated consecutive occurrences of the ERE would match. The values of m and n are decimal integers in the range 0 <= m<= n<= {RE_DUP_MAX}, where m specifies the exact or minimum number of occurrences and n specifies the maximum number of occurrences. The expression "{m}" matches exactly m occurrences of the preceding ERE, "{m,}" matches at least m occurrences, and "{m,n}" matches any number of occurrences between m and n, inclusive.
Manpage regex(7) hat geschrieben: A bound is '{' followed by an unsigned decimal integer,
possibly followed by ',' possibly followed by another
unsigned decimal integer, always followed by '}'.

Huo hat geschrieben: ↑ zum Beitrag ↑
25.05.2022 01:43:36
5) Erklaere die RE: `**'. Auf was wird sie matchen?
Uff! Meine erste Vermutung: Der erste Stern wird literal interpretiert, da nichts vor ihm steht, der zweite Stern hingegen als Quantor. Die RE "sollte" also auf beliebig viele aufeinander folgende Sterne matchen, einschließlich null Sterne. grep -o '**' hält sich auch schön brav an meine Vermutung, nicht jedoch egrep -o '**', das nichts ausgibt.

Zweite Vermutung: Der erste Stern wird als Quantor auf den leeren String angewendet. Der zweite Stern ist dann redundant, also verzichtbar. Im Grunde ist sogar der erste Stern verzichtbar, da sowohl die mehrmalige Wiederholung als auch das Weglassen eines leeren (!) Strings sinnlos ist. Diese Hypothese wird dadurch bestätigt, dass egrep '**' alle Zeilen eines Textes ausgibt (der leere String ist halt Teilmenge aller Zeilen), egrep -o '**' jedoch nichts (weil es keine passenden nicht leeren Teile gibt, die ausgegeben werden könnten). Das gleiche Verhalten zeigt egrep für die REs '*' und '' (leere RE).
Bezugnehmend auf deine Anmerkung zu den theoretischen Aufgaben beim Teil 07 koennte ich hier nun sagen, dass das auch so eine Aufgabe war: damit ihr darueber nachdenkt, was sein koennte und prueft was ist und wozu man das brauchen koennte. (Oder ich bekenne, dass ich gar nicht so weit gedacht habe, sondern die Aufgabe einfach mal gestellt habe ohne schon die Antwort im Kopf gehabt zu haben. :oops: )

Die Antwort jedenfalls findet man wenn man einen Blick in POSIX wirft ;-) :
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04_06 hat geschrieben: The behavior of multiple adjacent duplication symbols ( '+', '*', '?', and
intervals) produces undefined results.
Der Fall ist also nicht definiert. Was passiert haengt davon ab welche Implementierung man verwendet.

Vielleicht motiviert das auch nochmal dazu, nun, wo wir alle Aspekte von EREs erkundet haben, ab und an mal einen Blick in POSIX zu werfen wenn ihr euch mit solchen schwierigeren Fragen befasst.

Huo hat geschrieben: ↑ zum Beitrag ↑
25.05.2022 01:43:36
8) Matche den Inhalt eines Single-Quoted Strings (dieser kann das Single-Quote nicht enthalten).

Code: Alles auswählen

egrep "'[^']*'"
Es werden allerdings die Single Quotes mit gematcht. Einen Regulären Ausdruck, der nur den String innerhalb der Quotes matcht, habe ich nicht gefunden (vielleicht gar nicht möglich?).
Du hast recht, dass es mit EREs nicht moeglich ist den Inhalt eines gequoteten Strings zu matchen *ohne* die Quotes. Mit Lookaheads und Lookbehinds von PCREs ist das moeglich.


Btw: Waehrend es bei einzeichigen Endemarkern (wie bei Quotes) mit einer invertierten Zeichenklasse gearbeitet werden kann, um zwei quoted Strings auf einer Zeile separat zu matchen, geht das bei einem mehrzeichigen Endmarker (wie bei ``ENDE'') so nicht:

Code: Alles auswählen

:-Q echo "xxx 'foo' xxx 'bar' xxx" | egrep -o "'[^']+'" 
'foo'
'bar'

:-Q echo "xxx STARTfooENDE xxx STARTbarENDE xxx" | egrep -o "START.+ENDE"   
STARTfooENDE xxx STARTbarENDE

Huo hat geschrieben: ↑ zum Beitrag ↑
25.05.2022 01:43:36
11) Finde ein sinnhaftes Praxisbeispiel fuer eine RE mit Punkt aber ohne Quantoren.
Ein wirklich sinnhaftes natürlichsprachiges Beispiel ist m.E. nicht möglich wegen der Beliebigkeit, die der Punkt repräsentiert. Man könnte aber mit

Code: Alles auswählen

egrep '"."'
nach doppelt gequoteten Strings suchen, die genau ein Zeichen umfassen – etwa in einem Text, der einzelne so gequotete Zeichen erklärt, definiert oder kodiert ...
Ihr habt schon recht, dass man meist etwas Definierteres als den Punkt verwenden wollen wuerde, allerdings verwende ich in der Praxis oft genug sowas:

Code: Alles auswählen

<h.>
... um alle Ueberschriften in einem HTML-Dokument rauszusuchen. (Natuerlich waere XPath korrekter, aber oft will ich es nur ganz kurz mal sehen und der unperfekte Aufruf von egrep mit dem Punkt ist das was fuer mich am schnellsten funktioniert.)

Auch kann man mit dem Punkt alle einbuchstabigen HTML-Tags suchen: oder alle literalen chars in C: Bei wenigen Wiederholungen tippe ich lieber mehrere Punkte als geschweifte Klammern weil sich das schneller tippen laesst, z.B.:

Code: Alles auswählen

egrep -x '....' /usr/disc/words
... um alle vierbuchstabigen Woerter aus dem Woerterbuch auszugeben.

Auch wenn Punkte meist vor Quantoren stehen, so koennen sie auch ohne Quantoren sinnvoll sein.

(Btw: Bei BREs, die kein Plus haben, realisiert man `.+' mittels `..*' -- der erste Punkt hat hier auch keinen Quantor.)
Use ed once in a while!

Antworten