Fehler mit regulärem Ausdruck

Für allgemeine Fragen zur Programmierung mit PureBasic.
Tanaghra
Beiträge: 28
Registriert: 13.05.2017 01:44

Fehler mit regulärem Ausdruck

Beitrag von Tanaghra »

ich erschließe für mich gerade die Anwendung regulärer Ausdrücke und bin auf ein Programmverhalten gestoßen, das ich mir nicht erklären kann. Folgender Kode, bei dem im String zdZk alle vorkommenden "dass" durch "daß" ersetzt werden sollen (also eine Art Neue-in-alte-Rechtschreibung-Umwandler) funktioniert einwandfrei:

Code: Alles auswählen

Define.s zdZk ; zu durchsuchende Zeichenkette
zdZk="Da lagen einige junge Schwalben zerschmettert am Boden. Erstaunt "+
"untersuchte ich die Sache und fand heraus, dass die Schwalben selbst ihre "+
"Jungen aus den Nestern geworfen hatten!"

CreateRegularExpression(0, "dass\b")
zdZk=ReplaceRegularExpression(0, zdZk, "daß")
FreeRegularExpression(0)
Debug zdZk
Das "dass" in der zweiten Zeile wird wie gewünscht durch "daß" ersetzt.

Nun ist die eigentliche Anwendung natürlich um einiges komplexer: Ich habe eine Datei erstellt, bei der in jeder Zeile Suchausdruck und Ersetzungstext nebeneinander stehen und manche Zeilen wie oben den regulären Ausdurck \b (Wortgrenze) enthalten; später sollen ausgefeiltere reguläre Ausdrücke dazukommen dürfen. Sie sieht etwa so aus:
dass\b daß
Essst Eßst
ewusst ewußt
isschen ißchen
lässt\b läßt
lussst lußst
Missst Mißst
musst mußt
usw.
Die Idee ist dabei, diese Datei mit Such- und Ersetzungsausdrücken auf Textdateien in neuer Rechtschreibung anzuwenden und sie in die alte Rechtschreibung zurückzuüberführen. Da die umzuwandelnden Dateien z.T. sehr groß sind, wird deren Inhalt zuerst in den Arbeitsspeicher und vor dort in einen String geschrieben (dieser Teil des Kodes funktioniert). Dieser String wird dann durchsucht und alle vorkommenden Wörter in alter Rechtschreibung ersetzt. Im folgenden Beispiel ist der Inhalt der Datei zuD identisch mit dem des Strings zdZk von oben:

Code: Alles auswählen

#Ed="D:\Ersetzung neue Rechtschreibung Wortliste.txt"
Define KrA  ; Kennzeichner regulärer Ausdruck
Define.s zuD, ZmrA, rA, Wed ; zu überprüfende Datei, (Zeile mit) regulärem Ausdruck, Wort ersetzen durch

zuD="D:\umzuwandelnder Text.txt"
ReadFile(0, #Ed, #PB_Unicode) ; Datei mit Suchmustern öffnen
If ReadFile(1, zuD, #PB_Unicode)  ; Öffnen der Datei erfolgreich
  ReadStringFormat(1) ; setzt den Dateizeiger an das Ende der BOM
  Define *P, Dl, Di.s ; Puffer, Dateilänge, Dateiinhalt
  Dl=Lof(1)
  *P=AllocateMemory(Dl, #PB_Memory_NoClear) ;   
  If *P
    ReadData(1, *P, Dl) ; Datei ab Adresse *P in den Puffer schreiben
    Di=PeekS(*P)    ; liest den kompletten Puffer aus und schreibt 
    FreeMemory(*P)  ; ihn in die Zeichenkette Di
  EndIf
  CloseFile(1)
EndIf

While Not Eof(0)
  ZmrA=ReadString(0) ; Zeile mit regulärem Ausdruck einlesen
  rA=StringField(ZmrA, 1, " ")  ; regulären Ausdruck extrahieren
  Wed=StringField(ZmrA, 2, " ") ; Ersetzungsausdruck extrahieren
  KrA=CreateRegularExpression(#PB_Any, rA)
  Di=ReplaceRegularExpression(KrA, Di, Wed)
  Debug Di
  FreeRegularExpression(KrA)
Wend 
CloseFile(0)  ; Datei mit Suchmustern schließen

If CreateFile(2, zuD, #PB_Unicode) ; Pfad zur Zieldatei
  WriteStringFormat(2, #PB_Unicode)
  WriteString(2, Di): CloseFile(2)
EndIf
Bis zur Zeile

Code: Alles auswählen

KrA=CreateRegularExpression(#PB_Any, rA)
in der While-Wend-Schleife funktioniert alles perfekt. Aber die Ersetzung von "dass" in "daß" in der Zeile darauf findet nicht statt, d.h. der String Di bleibt unverändert. Obwohl die eingelesene Datei zuD den gleichen Inhalt hat wie oben der String zdZk, findet in ihr nicht die gewünschte Ersetzung statt. Wieso?
Windows 7 x64; geposteter Kode bezieht sich (sofern nicht anders angegeben) immer auf das aktuellste PureBasic 64-Bit

Erst wenn man es seiner Schwiegermutter erklären kann, hat man es verstanden.
As gsündeste is oiwei guad essn und dringa und ned grang wern.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Fehler mit regulärem Ausdruck

Beitrag von STARGÅTE »

Da ich den zweiten Code nicht ausführen kann, kann ich nur vermuten, dass es auch in der Suchmusterdatei (File 0) einen BOM gibt. Diesen ließt du aber nicht aus (wie du es bei File 1 machst). Somit ließt du die erste Zeite des Suchmusters mit dem BOM ein, was du dann später natürlich nicht finden kannst.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

Re: Fehler mit regulärem Ausdruck

Beitrag von #NULL »

- Wie Stargate bereits sagte würdest du den BOM mit im String haben.
- Bist du sicher das du die Dateien als UTF-16 (#PB_Unicode) lesen willst? Normalerweise würdest du den BOM auslesen und dann als Format-Flag weiterreichen.
- Du kannst ReadString() mit #PB_File_IgnoreEOL verwenden um alle Zeilen in einen String zu lesen.
- Eventuell willst du den BOM aus der Quelldatei wieder in die Ausgabedatei schreiben (wird im folgenden Code nicht gemacht)

Code: Alles auswählen

;#Ed="D:\Ersetzung neue Rechtschreibung Wortliste.txt"
#Ed="/home/user/Desktop/tmp23regexreplace1.txt"

Define KrA  ; Kennzeichner regulärer Ausdruck
Define.s zuD, ZmrA, rA, Wed ; zu überprüfende Datei, (Zeile mit) regulärem Ausdruck, Wort ersetzen durch

;zuD="D:\umzuwandelnder Text.txt"
zuD="/home/user/Desktop/tmp23regexreplace2.txt"

If ReadFile(0, #Ed) ; Datei mit Suchmustern öffnen
  bom0 = ReadStringFormat(0)
  
  If ReadFile(1, zuD)  ; Öffnen der Datei erfolgreich
    bom1 = ReadStringFormat(1)       ; setzt den Dateizeiger an das Ende der BOM
    Define Di.s = ReadString(1, bom1 | #PB_File_IgnoreEOL)
;     Define *P, Dl, Di.s ; Puffer, Dateilänge, Dateiinhalt
;     Dl=Lof(1)
;     *P=AllocateMemory(Dl, #PB_Memory_NoClear) ;   
;     If *P
;       ReadData(1, *P, Dl) ; Datei ab Adresse *P in den Puffer schreiben
;       Di=PeekS(*P)    ; liest den kompletten Puffer aus und schreibt
;       FreeMemory(*P)  ; ihn in die Zeichenkette Di
;     EndIf
    Debug "di: " + Di
    CloseFile(1)
  EndIf
  
  While Not Eof(0)
    ZmrA=ReadString(0, bom0) ; Zeile mit regulärem Ausdruck einlesen
    rA=StringField(ZmrA, 1, " ")  ; regulären Ausdruck extrahieren
    Wed=StringField(ZmrA, 2, " ") ; Ersetzungsausdruck extrahieren
    KrA=CreateRegularExpression(#PB_Any, rA)
    Di=ReplaceRegularExpression(KrA, Di, Wed)
    Debug Di
    FreeRegularExpression(KrA)
  Wend
  CloseFile(0)  ; Datei mit Suchmustern schließen
EndIf

zuD2.s = zuD + ".2.txt"
If CreateFile(2, zuD2) ; Pfad zur Zieldatei
  WriteStringFormat(2, #PB_UTF8)
  WriteString(2, Di): CloseFile(2)
EndIf
my pb stuff..
Bild..jedenfalls war das mal so.
Tanaghra
Beiträge: 28
Registriert: 13.05.2017 01:44

Re: Fehler mit regulärem Ausdruck

Beitrag von Tanaghra »

Danke für Eure Antworten. Ich bin kurz nach dem Post selbst auf den Fehler gekommen, es lag tatsächlich an dem fehlenden ReadStringFormat für die erste Datei. Was ich nicht so gut am Debugger finde, ist, daß er die BOM nicht anzeigt, wenn man mit dem Mauszeiger auf die Variable rA fährt, auch nicht in irgendeiner symbolischen Form. Der VisualBasic-Debugger tut das zumindest bei CR und LF, wenn der Font das zuläßt, also grundsätzlich könnte man wohl auch Sonderzeichen irgendwie grafisch sichtbar machen. Weil sonst sieht es so aus, als würde die Variable genau den Inhalt haben, der gewünscht ist, und irrt sich sehr.
Bist du sicher das du die Dateien als UTF-16 (#PB_Unicode) lesen willst? Normalerweise würdest du den BOM auslesen und dann als Format-Flag weiterreichen.
Ich bin mir nicht sicher, was Du damit meinst. Die Dateien sind jedenfalls beide im UTF-16-Format – alle meine Textdateien sind das, weil ich häufig bi- und multilinguale Texte habe (Deutsch/Russisch/Altgriechisch gemischt).
Überhaupt fühle ich mich beim Thema "BOM" noch nicht sattelfest; ich weiß nur das, was die Hilfe dazu schreibt, also daß sie bei UTF-16-Dateien in der Regel am Dateianfang steht. Wie man am besten mit ihr umgeht, wenn man den String, der die gesamte Datei enthält, manipulieren will (Überspringen, Ausschneiden/Kopieren und nach der Veränderung wieder einfügen) – keine Ahnung. Was ich allerdings beobachtet habe, ist, daß es offenbar nicht genügt,

Code: Alles auswählen

WriteStringFormat(2, #PB_Unicode)
einfach vor

Code: Alles auswählen

WriteString(2, Di): CloseFile(2)
zu setzen, wie am Ende meines Kodes. Manchmal (aber nicht immer) tauchen in der durch CreateFile erzeugten neuen (manipulierten) Datei seltsame asiatische Zeichen auf.
Windows 7 x64; geposteter Kode bezieht sich (sofern nicht anders angegeben) immer auf das aktuellste PureBasic 64-Bit

Erst wenn man es seiner Schwiegermutter erklären kann, hat man es verstanden.
As gsündeste is oiwei guad essn und dringa und ned grang wern.
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

Re: Fehler mit regulärem Ausdruck

Beitrag von #NULL »

Das Format-Flag das du bei WriteStringFormat() verwendest müsstest du dann auch bei WriteString() mit angeben.
my pb stuff..
Bild..jedenfalls war das mal so.
Antworten