ubuntuusers.de

Problem mit regexec()

Status: Gelöst | Ubuntu-Version: Xubuntu 14.04 (Trusty Tahr)
Antworten |

Dakuan

Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Ich bin da kürzlich über ein Problem gestolpert. Ursprünglich wollte ich alle Datensätze finden, die mit einem "New Line" enden. Das hätte gehen können, da alle Datensätze ein Formular ohne Leerzeilen enthalten.

Als Suchmuster habe ich daher "^$" probiert. Innerhalb des Textes funktioniert das auch fast problemlos, wenn man beachtet das bei einem Treffer der Start-Offset und der End-Offset gleich sind.

Die vermeintliche Leerzeile am Ende des Textes wird auch erkannt. Aber wenn es da mehrere "\n" gibt, fehlt immer die letzte Leerzeile. Ich habe dann versucht diesen "Mangel" trickreich zu beheben, musste dann aber feststellen, das ich diesen Treffer im Editor nicht durch Highlighting darstellen kann.

Der andere Fall, also bei einem Text wie: "aaa\n" das Ende nicht als Leerzeile zu erkennen, funktioniert auch nicht richtig. Da sind dann auch einige Tricks nötig.

Das wirft für mich die Frage auf, welches der beiden Verhaltensmuster ich anstreben sollte. Oder anders gefragt, Was würde ein Anwender erwarten. Technisch gesehen ist ja die Position hinter dem letzten "\n" schon hinter dem eigentlichen Text, weshalb der Editor diese Position nicht "highlighten" kann.

Im Anhang kann man das sehen. Der Text ist: "cccc\n\nc1c1\n".

Ich hoffe das Problem einigermaßen verständlich beschrieben zu haben.

Bilder

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

Dakuan schrieb:

Ich hoffe das Problem einigermaßen verständlich beschrieben zu haben.

Ich muss sagen: Nein. ☺

Geht es um das Finden von Leerzeilen oder Zeilenenden?

Um das Finden oder das highlighten?

Wie Du es findest oder ob Du es finden sollst?

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Geht es um das Finden von Leerzeilen oder Zeilenenden?

Also erstmal geht es um das finden von leeren Zeilen, da "^$" ja ein gültiges Muster ist.

Zusätzlich geht es auch um die Frage, ob bei einem Text, der mit einem Zeilenende aufhört, auch eine leere Zeile erkannt werden soll(te). Diese kann dann im Editor allerdings nicht markiert werden (so wie im Bild gezeigt), was ein Anwender aber wahrscheinlich erwarten würde.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13174

Dakuan schrieb:

Geht es um das Finden von Leerzeilen oder Zeilenenden?

Also erstmal geht es um das finden von leeren Zeilen, da "^$" ja ein gültiges Muster ist.

Schon den Satz verstehe ich nicht. Was macht das "da" da? Ja, "^$" ist ein gültiges Muster und ja, man kann damit Leerzeilen irgendwo in einem Dokument finden. Aber welche Werkzeuge verwendest Du? Und geht es um zeilenweise Abarbeiten (wie die ganzen Kommandozeilentools der grep-Familie) oder willst Du der Regex-Engine einen kompletten Text vorwerfen?

Zusätzlich geht es auch um die Frage, ob bei einem Text, der mit einem Zeilenende aufhört, auch eine leere Zeile erkannt werden soll(te). Diese kann dann im Editor allerdings nicht markiert werden (so wie im Bild gezeigt), was ein Anwender aber wahrscheinlich erwarten würde.

Das ist aber eine ganz andere Diskussion, die man nicht technisch allgemein beantworten kann. Das hängt von Vorlieben und Anwendungsfällen ab. Ich denke, das sollten wir in einem separaten Thema diskutieren, gerade auch, weil das Potential hat auszuufern. ☺

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4673

Wohnort: Berlin

Das '\n' steht in Linux für ein Zeilenende, also es beendet eine Zeile. Umgekehrt müsste alles was man als Zeile betrachten will, auch mit einem '\n' enden. Demnach ist die ”Zeile” nach dem letzten Zeilenende in einem Editor keine Zeile. Die wird ja beispielsweise von Programmen wie wc auch nicht mitgezählt. Das man im Editor den Cursor dort platzieren kann, sehe ich als Notwendigkeit, denn wie sollte man sonst nach der letzten Zeile eine weitere hinzufügen.

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Aber welche Werkzeuge verwendest Du? Und geht es um zeilenweise Abarbeiten (wie die ganzen Kommandozeilentools der grep-Familie) oder willst Du der Regex-Engine einen kompletten Text vorwerfen?

Ich verwende die C-Funktion regexec(). Ich dachte das wäre durch die Schreibweise in der Überschrift klar. Und, ja, die Funktion bekommt einen kompletten Text angeboten, wobei sich dann aber immer der Beginn einer neuen Suche nach dem Ende des letzten Treffers richtet.

Momentan neige ich dazu, mich der Sichtweise von Marc_BlackJack_Rintsch anzuschließen.

@Marc_BlackJack_Rintsch

Die wird ja beispielsweise von Programmen wie wc auch nicht mitgezählt.

Ok, dann nehme ich das mal als Vorbild.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Wenn ich es annähernd richtig verstehe, geht es Dir hier um die Frage, ob eine letzte Zeile ohne "\n" am Ende noch eine Zeile ist ?

Wie Robert auch schon gesagt hat, kann man das so oder so sehen:

track@track:~$ echo -n 'a
b
c'  |  wc
      2       3       5
track@track:~$ echo -n 'a
b
c'  |  sed '= '
1
a
2
b
3 

sed zählt sie mit, wc nicht. Wie Du das handhaben willst, musst Du Dir überlegen, je nach Verwendung und persönlicher Vorliebe.

LG,

track

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Wie Robert auch schon gesagt hat, kann man das so oder so sehen:

Ja, ich denke inzwischen, dass man sich darüber Gedanken machen sollte, bevor man diese Funktion mit "^$" anwendet.

Irritierend ist in diesem Fall das Verhalten von regexec(). Wird ein einzelner Zeilenwechsel '\n' gefunden, so wird als 'start-offset' und 'end-offset' der gleiche Index verwendet, d.h. der Treffer hat die Länge 0. Wenn jetzt der End-Offset direkt als Ausgangspunkt für eine weitere Suche verwendet wird, hängt das Programm in einer Endlosschleife, es ist also eine Sonderbehandlung erforderlich.

Zusätzlich wird auch ein leerer String, also nur ein Zeiger auf das beendende Nullbyte, als Treffer gewertet, wobei hier ebenfalls Start- und End Offset gleich sind. Mit diesem (überaschendem) Verhalten von regexec() kann man beide Sichtweisen abbilden. Das hängt dann von der Definition der Endebedingungen und von der Bewertung der Ergebnisse ab.

Ich hatte kurzzeitig überlegt, das durch ein Flag steuerbar zu machen, aber das gestaltete sich als zu unübersichtlich. Ich sah da nur die Möglichkeit 2 unterschiedliche Bewertungsfunktionen zu implementieren. Die habe ich aber erstmal zurück gestellt, da mir der Nutzen im Verhältnis zum Aufwand zu gering erschien.

Wenn ich es annähernd richtig verstehe, geht es Dir hier um die Frage, ob eine letzte Zeile ohne "\n" am Ende noch eine Zeile ist ?

Das war der eigentliche Auslöser, abgesehen davon das allein die Eingabe des Suchmusters die ursprüngliche Programmversion in eine Endlosschleife getrieben hatte. Ich habe da eine Sammlung von kurzen Text Dateien (etwa 5000) die von anderen Programmen weiter verarbeitet und ergänzt werden. Wenn da beim Ergänzen mal zusätzliche Leerzeilen erzeugt werden und mal nicht, ist das beim Endergebnis von der Optik eher störend.

Mit "Bewertung der Treffer" meine ich, das der Anwender sich überlegen muss, ob es sich bei einem Treffer, bei dem der gefundene Start-Offset, der hinter der Textlänge liegt, um ein gültiges Ergebnis handelt. Das währe nur der Fall, wenn die letzte Zeile "xxx\n" auch als Leerzeile bewerten will.

Das sind wirklich 2 unterschiedliche Betrachtungsweisen, die nicht so einfach unter einen Hut zu bringen sind und darüber muss man sich als Programmierer erstmal klar werden, da dies aus der Doku nicht sofort ersichtlich ist (die meisten Beispielprogramme suchen ja nur nach einem Treffer, ohne diesen, wie in einem Texteditor, anzeigen zu wollen oder danach eine Fortsetzung der Suche zu wollen).

In meinen Anwendungen gehe ich erstmal davon aus, das die letzte Zeile, die mit "xx\n" endet, nicht leer ist und nicht von einer leeren Zeile verfolgt wird. Anderenfalls hätte ich ca. 98% Treffer.

Antworten |