Kleiner regulärer Ausdruck

Crys

Lt. Commander
Registriert
Apr. 2009
Beiträge
1.639
Ich und die Regulärenausdrücke, wir werden nie Freunde ... :D

Ich möchte (in AutoIt, das sollte aber Nebensache sein) ein Dokument regulärer durchsuchen und Ausdrücke ersetzten lassen.

Ein Beispiel:
Es soll das Wort "Baum" immer mit "\ac{}" also zu "\ac{Baum}" umschlossen werden.
Das soll aber nur geschehen, wenn vor dem Wort ein Leerzeichen ist oder einen Zeilenumbruch und wenn hinter dem Wort ein Minus, Komma, Punkt oder Leerzeichen ist.

Meiner Auffassung nach geht das so:
Suche nach: "([\s]+)(Baum)([\s\.,\-]+)"
Ersetzte durch: "$1\\ac\{$2\}$3"

Es passieren aber komische Dinge, bei jedem Durchlauf was anders ... was mache ich falsch? :freak:
 
$1 $2 $3 sind die Inhalte der 3 Klammern ?? erklär mal die syntax, weil der ablauf ist quasi richtig wenn der Suche nach string richtig ist

MfG Schlummi
 
Code:
[ \x0d\x0a]baum[-,\.\x20]
Funktioniert in Notepad++ wunderbar.
 
@ Schlummi:
Der syntax sollte doch überall gleich sein!?
In php, c++, autoit bin ich bisher immer mit dem selben Syntax gefahren ...

@ Yuuri:
Was bedeuten die x-Ausdrücke?
Bei mir klappt das nicht

Hier ein Muster-Code:
Code:
Muss geändert werden:
Baum Baum, Baum. Baum Baum Baum-

Darf nicht geändert werden
baum ,Baum .Baum -Baum {Baum Baum} Baumhaus HausBaum
 
\xa bezeichnet einfach den hexadezimalen Wert eines Zeichens. Sieh mal in der ASCII-Tabelle nach. \x0a ist bspw. \n, \x0d ist \r (Windows \r\n, Linux \n, Mac \r).

Bei deinem Beispiel würde
Code:
Muss geändert werden:
\ac{Baum}Baum,\ac{Baum}\ac{Baum}Baum\ac{Baum}
 
Darf nicht geändert werden
\ac{Baum},Baum .Baum -Baum {Baum Baum} Baumhaus HausBaum
herauskommen. Das erste \ac{Baum} in der zweiten Zeile kommt natürlich durch den Umbruch zustande.

Der Regex wird aber nicht komplett auf die erste Zeile angewandt werden, da das Leerzeichen beim ersten Wort nicht zum Zweiten gehört. Du könntest den Regex dann dahingehend
Code:
[ \x0d\x0a]?baum[-,\.\x20]
abwandeln, sodass das Leerzeichen davor optional wäre, allerdings beeinflusst du damit natürlich genauso die zweite Zeile.

Zu deiner ersten Frage: Du nutzt hier PCRE (Perl compatible regular expressions), es gibt aber bspw. noch POSIX (http://en.wikipedia.org/wiki/Regular_expression#Syntax) und jede Menge weitere teilweise sehr einfache Implementierungen (nur für rudimentäre Sachen natürlich). Grep bspw. gibt folgende Möglichkeiten für reguläre Ausdrücke:
Code:
  -E, --extended-regexp     PATTERN is an extended regular expression (ERE)
  -G, --basic-regexp        PATTERN is a basic regular expression (BRE)
  -P, --perl-regexp         PATTERN is a Perl regular expression
  -e, --regexp=PATTERN      use PATTERN for matching
 
Crys schrieb:
Ich möchte (in AutoIt, das sollte aber Nebensache sein) ein Dokument regulärer durchsuchen und Ausdrücke ersetzten lassen.
Nein, das ist (leider) keine Nebensache, jede Implementation (AutoIt, Java, Perl, C#, Notepad++, usw.) hat so ihre kleinen Eigenheiten ;)

Siehe http://www.autoitscript.com/autoit3/docs/functions/StringRegExp.htm

Code:
Muss geändert werden:
    Baum Baum, Baum. Baum Baum Baum-
     
    Darf nicht geändert werden
    baum ,Baum .Baum -Baum {Baum Baum} Baumhaus HausBaum

Mein Vorschlag

Code:
Local $sInput = "Baum Baum, Baum. Baum Baum Baum-"
Local $sOutput = StringRegExpReplace($sInput, "([\s ]?)(Baum)([ \.,\-])", "$1\\ac{$2}$3")
Display($sInput, $sOutput)

Local $sInput = "baum ,Baum .Baum -Baum {Baum Baum} Baumhaus HausBaum"
Local $sOutput = StringRegExpReplace($sInput, "([\s ]?)(Baum)([ \.,\-])", "$1\\ac{$2}$3")
Display($sInput, $sOutput)


Func Display($sInput, $sOutput)
    Local $sMsg = StringFormat("Input:\t%s\n\nOutput:\t%s", $sInput, $sOutput)
    MsgBox(0, "Results", $sMsg)
EndFunc

ersetzt und unterlässt nach Deinen Vorgaben wo es soll ;)


HTH

BigNum
 
Oh ha. Arbeite hier mit meinem php Handbuch, indem auch was über RegEx steht ... schnell weg leg.
War der festen Überzeugung, dass das alles gleich ist ... soso :D

Yuuri schrieb:
Der Regex wird aber nicht komplett auf die erste Zeile angewandt werden, da das Leerzeichen beim ersten Wort nicht zum Zweiten gehört.
Ah, danke. Deshalb hat der bei jeden Durchgang was anderes gemacht :)

BigNum schrieb:
ersetzt und unterlässt nach Deinen Vorgaben wo es soll ;)
Leider nichts ganz.
Alles in der letzten Zeile soll nach dem ersetzen so sein, wie vorher. Dort soll also nichts ersetzt werden. Ich probiert gerade noch rum ...


Aber schon mal danke euch beiden, man lernt nie aus :cool_alt:
Ergänzung ()

.

Vielen Dank, das war es doch schon!
Das Beispiel war nur nicht realitätsnah, hab's geändert und schon tut's :freaky:


Ich hab nur noch festgestellt, das ich noch nicht an der Lösung bin.
Wenn das Wort jetzt in einer geschweiften Klammer mit bestimmten Suffix ist, dann soll es auch nie ersetzt werden.

Hier ein Beispiel:
Code:
$suchen = "([\s ])(Baum)([ \.,\-])"
$ersetzten =  "$1\\ac{$2}$3"

; Hier soll alles esetzt werden
Local $sInput = @CRLF & "Baum ist ein Baum, ist ein Baum. ist ein Baum ist ein Baum ist ein Baum-"
Local $sOutput = StringRegExpReplace($sInput, $suchen, $ersetzten)
Display($sInput, $sOutput)

; Hier soll nichts ersetzt werden
Local $sInput = @CRLF & "baum ist kein ,Baum ist kein .Baum ist kein -Baum ist kein {Baum ist kein Baum} ist kein Baumhaus ist kein HausBaum"
Local $sOutput = StringRegExpReplace($sInput, $suchen, $ersetzten)
Display($sInput, $sOutput)

; Hier soll alles esetzt werden
Local $sInput = @CRLF & "\Buche{Ein Baum ist kein Baum oder doch}"
Local $sOutput = StringRegExpReplace($sInput, $suchen, $ersetzten)
Display($sInput, $sOutput)

; Hier soll nichts ersetzt werden
Local $sInput = @CRLF & "\Eiche{Ein Baum ist ein Baum oder doch nicht}"
Local $sOutput = StringRegExpReplace($sInput, $suchen, $ersetzten)
Display($sInput, $sOutput)

Func Display($sInput, $sOutput)
    Local $sMsg = StringFormat("Input:\t%s\n\nOutput:\t%s", $sInput, $sOutput)
    MsgBox(0, "Results", $sMsg)
EndFunc
Wenn Baum in \Eiche{#} ist, dann soll Baum auch nicht ersetzt werden.
Habe da gerade keinen Ansatz dafür, muss man das mit einen extra RegEx machen?
Wie bekomme ich das hin? :D
 
Crys schrieb:
Wenn Baum in \Eiche{#} ist, dann soll Baum auch nicht ersetzt werden.
Habe da gerade keinen Ansatz dafür, muss man das mit einen extra RegEx machen?
Wie bekomme ich das hin? :D
Du brauchst eine eigene RegEx, die Dir im Fall "Eiche{" den Ausdruck in drei Teile teilt (links von "Eiche", innerhalb der geschweiften Klammern und rechts davon) und dann nur die Teile "Links" und "Rechts" der RegEx "Baum" zuführt.


HTH

BigNum
 
@Yuuri:
Du kannst mit Lookarounds (oder etwas anderes) aber nicht beide Bedingungen

Es soll das Wort "Baum" immer mit "\ac{}" also zu "\ac{Baum}" umschlossen werden.
Das soll aber nur geschehen, wenn vor dem Wort ein Leerzeichen ist oder einen Zeilenumbruch und wenn hinter dem Wort ein Minus, Komma, Punkt oder Leerzeichen ist.

und

Wenn Baum in \Eiche{#} ist, dann soll Baum auch nicht ersetzt werden.

mit einer Regex erschlagen.
Wenn Du eine findest behaupte ich naturlich ab dann das Gegenteil ;)
Das wird aber nicht passieren :D


Grüße

BigNum
 
Genau so oder wie? ;)
 

Anhänge

  • regex.png
    regex.png
    16,6 KB · Aufrufe: 113
@Yuuri: Ich nix verstehn...

@Crys:
Die "Eichenlösung" lautet
Code:
$suchen = "([\s ])(Baum)([ \.,\-])"
$ersetzen = "$1\\ac{$2}$3"


Local $sInput = 'keine Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein Baum.'
Local $sOutput = MyReplace($sInput)
Display($sInput, $sOutput)

Local $sInput = 'seine Buche{Ein Baum ist ein Baum oder doch nicht} und mein Ahorn'
Local $sOutput = MyReplace($sInput)
Display($sInput, $sOutput)


Func MyReplace($str)
	Local $array = StringRegExp($str, '(.*?Eiche{)(.*)(}.*)', 1);
	If IsArray($array) Then
		return StringRegExpReplace($array[0], $suchen, $ersetzen) & $array[1] & StringRegExpReplace($array[2], $suchen, $ersetzen)
	Else
		return StringRegExpReplace($str, $suchen, $ersetzen)
	EndIf
EndFunc
  

Func Display($sInput, $sOutput)
    Local $sMsg = StringFormat("Input:\t%s\n\nOutput:\t%s", $sInput, $sOutput)
    MsgBox(0, "Results", $sMsg)
EndFunc


HTH

BigNum
 
@ Yuuri:
Verstehe leider auch nicht, was du genau meinst :)

@BigNum:
Danke, das ist es ... fast :D
Deine Zeilen sind perfekt, für das war ich dir als Beispiel gepostet habe.
Nur mein original geht länger, über mehrere Zeilen und Zeilenumbrüche. Und die Zeilenumbrüche machen mir Probleme.

Wenn ich das rekursiov mache, dann ersetzte der mir auch in den falschen Klammern die Wörter:
Code:
$suchen = "([\s ])(Baum)([ \.,\-])"
$ersetzen = "$1\\ac{$2}$3"

Local $sInput1 = 'keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein Baum.'
Local $sOutput = MyReplace($sInput1)
;Display($sInput1, $sOutput)

Local $sInput2 = 'seine \Buche{Ein Baum ist ein Baum oder doch nicht} und mein Ahorn und doch ein Baum.'
Local $sOutput = MyReplace($sInput2)
;Display($sInput2, $sOutput)

Local $sInput = $sInput1 & @CRLF & $sInput2 & @CRLF & $sInput1 & @CRLF & $sInput2
Local $sOutput = MyReplace($sInput)
Display($sInput, $sOutput)

Func MyReplace($str)
    ;Local $array = StringRegExp($str, '(.*?\\Eiche{)(.*)(}.*)', 1);
    Local $array = StringRegExp($str, '([\w\W]*?Eiche{)(.*)(}[\w\W]*)', 1);
    If IsArray($array) Then
        $array[2] = MyReplace($array[2])
        return StringRegExpReplace($array[0], $suchen, $ersetzen) & $array[1] & StringRegExpReplace($array[2], $suchen, $ersetzen)
    Else
        return StringRegExpReplace($str, $suchen, $ersetzen)
    EndIf
EndFunc
 
Func Display($sInput, $sOutput)
    Local $sMsg = StringFormat("Input:\t%s\n\nOutput:\t%s", $sInput, $sOutput)
    MsgBox(0, "Results", $sMsg)
EndFunc
 
Crys schrieb:
Nur mein original geht länger, über mehrere Zeilen und Zeilenumbrüche. Und die Zeilenumbrüche machen mir Probleme.

Wenn ich das rekursiov mache, dann ersetzte der mir auch in den falschen Klammern die Wörter:
Dann poste doch einen Beispieltext, bei dem es "schief" läuft und wie es idealerweise sein sollte...
 
Naja, wie in Zeile 12, von meinem geposteten Quelltext, im letzten Post.

keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein Baum.
seine \Buche{Ein Baum ist ein Baum oder doch nicht} und mein Ahorn und doch ein Baum.
keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein Baum.
seine \Buche{Ein Baum ist ein Baum oder doch nicht} und mein Ahorn und doch ein Baum.

sollte zu ...
keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein \ac{Baum}.
seine \Buche{Ein \ac{Baum} ist ein \ac{Baum} oder doch nicht} und mein Ahorn und doch ein \ac{Baum}.
keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein \ac{Baum}.
seine \Buche{Ein \ac{Baum} ist ein \ac{Baum} oder doch nicht} und mein Ahorn und doch ein \ac{Baum}.

... werden, wird aber (mit meinem letzten Beispiel) zu:
keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein \ac{Baum}.
seine \Buche{Ein \ac{Baum} ist ein \ac{Baum} oder doch nicht} und mein Ahorn und doch ein \ac{Baum}.
keine \Eiche{Ein \ac{Baum} ist ein \ac{Baum} oder doch nicht} und keine Linde und doch ein \ac{Baum}.
seine \Buche{Ein \ac{Baum} ist ein \ac{Baum oder doch nicht} und mein Ahorn und doch ein \ac{Baum}.
 
Ich denke das
Code:
$suchen = "([\s ])(Baum)([ \.,\-])"
$ersetzen = "$1\\ac{$2}$3"

Local $sInput1 = 'keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein Baum.'
Local $sOutput = MyReplace($sInput1)
;Display($sInput1, $sOutput)

Local $sInput2 = 'seine \Buche{Ein Baum ist ein Baum oder doch nicht} und mein Ahorn und doch ein Baum.'
Local $sOutput = MyReplace($sInput2)
;Display($sInput2, $sOutput)

Local $sInput = $sInput1 & @CRLF & $sInput2 & @CRLF & $sInput1 & @CRLF & $sInput2
Local $sOutput = MyReplace($sInput)
Display($sInput, $sOutput)

Func MyReplace($str)
    Local $array = StringRegExp($str, '(.*?\\Eiche{)(.*)(}.*)', 1);
    ;Local $array = StringRegExp($str, '([\w\W]*?Eiche{)(.*)(}[\w\W]*)', 1);
    If IsArray($array) Then
        ;return StringRegExpReplace($array[0], $suchen, $ersetzen) & $array[1] & StringRegExpReplace($array[2], $suchen, $ersetzen)
        return MyReplace($array[0]) & $array[1] & MyReplace($array[2])
    Else
        return StringRegExpReplace($str, $suchen, $ersetzen)
    EndIf
EndFunc
 
Func Display($sInput, $sOutput)
    Local $sMsg = StringFormat("Input:\t%s\n\nOutput:\t%s", $sInput, $sOutput)
    MsgBox(0, "Results", $sMsg)
EndFunc
sollte funktionieren ;)


HTH

BigNum
 
Hehe, nein :D
Du hast nur meine Auskommentiertung verschoben (Von Zeile 17 zu 18)!?
Mit dem [\w\W] werden auch Zeilenumbrüche mitbehandelt, mit dem . (Punkt) wertet der nur genau bis zum ersten Zeilenumbruch aus.
 
Die finale Version:

Code:
$suchen = "([\s ])(Baum)([ \.,\-])"
$ersetzen = "$1\\ac{$2}$3"

Local $sInput1 = 'keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein Baum.'
;Local $sOutput = MyReplace($sInput1)
;Display($sInput1, $sOutput)

Local $sInput2 = 'seine \Buche{Ein Baum ist ein Baum oder doch nicht} und mein Ahorn und doch ein Baum.'
;Local $sOutput = MyReplace($sInput2)
;Display($sInput2, $sOutput)

Local $sInput = $sInput1 & @CRLF & $sInput2 & @CRLF & $sInput1 & @CRLF & $sInput2
Local $sOutput = MyReplace($sInput)
Display($sInput, $sOutput)

Func MyReplace($str)
    Local $array = StringRegExp($str, '(?s)(.*?\\Eiche{)(.*?)(}.*)', 1);
    If IsArray($array) Then
        ;return StringRegExpReplace($array[0], $suchen, $ersetzen) & $array[1] & StringRegExpReplace($array[2], $suchen, $ersetzen)
        return MyReplace($array[0]) & $array[1] & MyReplace($array[2])
    Else
        return StringRegExpReplace($str, $suchen, $ersetzen)
    EndIf
EndFunc
 
Func Display($sInput, $sOutput)
    Local $sMsg = StringFormat("Input:\t%s\n\nOutput:\t%s", $sInput, $sOutput)
    MsgBox(0, "Results", $sMsg)
EndFunc

Der Fehler war dass (jetzt zitiere ich mich schon selber ;))
BigNum schrieb:
Nein, das ist (leider) keine Nebensache, jede Implementation (AutoIt, Java, Perl, C#, Notepad++, usw.) hat so ihre kleinen Eigenheiten
die RegEx-Implementation von AutoIt eine kleine Eigenheit hat, die andere Implementationen so nicht haben:
http://www.autoitscript.com/autoit3/docs/functions/StringRegExp.htm schrieb:
Note that special characters do not retain their special meanings inside a set, with the exception of \\, \^, \-,\[ and \] match the escaped character inside a set.
Ein "\s" innerhalb von eckigen Klammern funktioniert deshalb nicht (im Gegensatz zu allen anderen Implementationen die ich kenne).
Deshalb habe ich per "(?s)" das sog. "s"-Flag eingeschaltet, welches bewirkt, daß der Punkt "." auch Zeilenumbrüche konsumiert...

Ausserdem habe ich noch die Rekursion (Zeilen 19/20) geändert.


HTH

BigNum
 
He, vielen Dank. Ich habe das gestern noch so gelöst:
Code:
$suchen = "([\s ])(Baum)([ \.,\-])"
$ersetzen = "$1\\ac{$2}$3"

Local $sInput1 = 'keine \Eiche{Ein Baum ist ein Baum oder doch nicht} und keine Linde und doch ein Baum.'
;Local $sOutput = MyReplace($sInput1)
;Display($sInput1, $sOutput)

Local $sInput2 = 'seine \Buche{Ein Baum ist ein Baum oder doch nicht} und mein Ahorn und doch ein Baum.'
;Local $sOutput = MyReplace($sInput2)
;Display($sInput2, $sOutput)

Local $sInput = $sInput1 & @CRLF & $sInput2 & @CRLF & $sInput1 & @CRLF & $sInput2
Local $sOutput = MyReplace($sInput)
Display($sInput, $sOutput)

Func MyReplace($str)
    Local $array = StringRegExp($str, '([\w\W]*?Eiche{)(.*)(}[\w\W]*)', 1);
    If IsArray($array) Then
        return StringRegExpReplace($array[0], $suchen, $ersetzen) & $array[1] & MyReplace($array[2])
    Else
        return StringRegExpReplace($str, $suchen, $ersetzen)
    EndIf
EndFunc
 
Func Display($sInput, $sOutput)
    Local $sMsg = StringFormat("Input:\n%s\n\nOutput:\n%s", $sInput, $sOutput)
    MsgBox(0, "Results", $sMsg)
EndFunc
Ist eig. der Code von meinem letzten Post, nur habe ich das 2. StringRegExpReplace von $array[2] entfernt.
Bei deinem Code kommt genau das selbe raus.

Aber wieder viel dazugelernt. Danke für deine Ausführliche Hilfe, ich glaub jetzt ist das Thema geklärt :cool_alt:
 

Ähnliche Themen

O
JavaScript Regulärer Ausdruck
Antworten
3
Aufrufe
1.385
O
Zurück
Oben