PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Regular Expression-Frage


PHuV
2013-12-11, 16:56:39
Ich suche in Dateien nach Strings, die am Zeilenanfang mit einer Zahl anfangen, z.B.


990
000000
usw.
Wie formuliere ich nun korrekt einen String mit Nicht?
Das untere funktioniert nicht, hier findet er auch andere Zahlen am Zeilenanfang.
^[^990]
Das hier geht auch nicht.
^[^9][^9][^0]
Als positive Bedingung funktioniert ein String
^(990)
Nur wie mache ich das mit Nicht? :confused: Weil so formuliert gehts auch nicht
^(990)
^(^990)
^[^(990)]


Eine blöde Lösung ist diese hier:
^[^-9-9][^9-9][^0-0]

nalye
2013-12-11, 17:09:06
^[^0-9].*
Damit sollte das gehen, da sucht er alle Zeilen ab, die nicht mit Zahlen 0-9 beginnen. Also im Prinzip beginnt mit nicht 0-9 und weiterem Zeichen

PHuV
2013-12-11, 17:12:00
Ich brauche aber extakt den kompletten String mit 990 oder 000000, nicht mehr, nicht weniger. Mit Deiner Anweisung sortiert Du ja alle Dateianfänge mit
0xxxxx
1xxxxx
:
9xxxxx
aus. Ich brauche aber
990xxxx
000000xxxx
Sind Mandantennummern von einem SAP-System als Flatfile.

Monger
2013-12-11, 18:30:18
Ich verstehs ehrlich gesagt noch nicht. Was konkret willst du? Willst du vorne die Zahl wegschneiden und nur den Rest, oder willst du überprüfen ob da eine bestimmte Zahl steht? Willst du alle Strings denen eben keine Zahl vorsteht?

mMn missverstehst du auf jeden Fall die Zeichenklassen. [123] matcht nicht etwa auf einen String "123", sondern entweder "1", "2", oder "3". Sowas wie [990] macht deshalb auch keinen Sinn, weil es matcht entweder auf "0" oder auf "9".

Marscel
2013-12-11, 18:32:32
Sowas?

^(?!990)

Monger
2013-12-11, 18:34:55
Sowas?

^(?!990)
Ein Negative Look ahead. Klingt plausibel. Aber dann sollte halt dahinter noch was stehen, also:
^(?!990)\w+

Marscel
2013-12-11, 18:37:19
Ein Negative Look behind. Klingt plausibel. Aber dann sollte halt dahinter noch was stehen, also:

Ich bin nun auch nicht so sicher, was er genau machen möchte ;)

samm
2013-12-11, 22:07:37
Ich brauche aber
990xxxx
000000xxxx
Sind Mandantennummern von einem SAP-System als Flatfile.Also was ist denn mit "negativ" aus dem ersten Posting? Nun klingt es, als möchtest du einfach

^((990)|(0{6}).*)

Und in welcher Sprache/welcher Umgebung setzt du regex ein? Erstens können nicht alle Systeme alles, und zweitens gibt es ausser regex weitere bequeme Varianten, z.B. wenn du das Flatfile mit einer Nummer pro Zeile in einer .net Umgebung eingelesen hast z.B. mit Linq eine Liste aller Zeilen filtern etc.

Oder, weil du SAP nennst, wenn das Flatfile gar nicht die zwangsläufige Anfang der Verarbeitungskette ist sondern eine DB, kannst du die Nummern direkt schon in der Query, die der Ursprung des Files ist, filtern.

PHuV
2013-12-12, 10:45:20
Sowas?

^(?!990)
Funktioniert leider nicht.
Ein Negative Look ahead. Klingt plausibel. Aber dann sollte halt dahinter noch was stehen, also:
^(?!990)\w+
Klappt leider auch nicht.
[990] macht deshalb auch keinen Sinn, weil es matcht entweder auf "0" oder auf "9".
Richtig, genau das habe ich ja auch festgestellt.

Monger
2013-12-12, 10:53:41
Funktioniert leider nicht.

Klappt leider auch nicht.
Da wir nach wie vor am Rätselraten sind was du eigentlich versuchst zu tun, wäre ein bissl mehr Info vernünftig.
Außerdem: "klappt nicht" ist immer die beschissenste aller Antworten. Was genau klappt nicht? Kriegst du keinen Match? Steht im Match nicht drin was du erwartest? Mit was für Eingangsdaten testest du konkret?

Lern mal dich hier präziser auszudrücken.

PHuV
2013-12-12, 10:59:54
Da wir nach wie vor am Rätselraten sind was du eigentlich versuchst zu tun, wäre ein bissl mehr Info vernünftig.

Ich bin doch noch am Tippen.
Außerdem: "klappt nicht" ist immer die beschissenste aller Antworten. Was genau klappt nicht? Kriegst du keinen Match?
Richtig. Ich teste es per UltraEdit und PSPad. Ich tippe gerade die Erklärung, und bitte noch um Geduld, ist was längeres.

PHuV
2013-12-12, 11:10:24
Ganz einfach, ich habe generierte Dateien als Export von einem SAP-System, auf deren Generierung kein Einfluß vorhanden ist. Sprich, eine internationale Abteilung schreibt diese einfach mal so raus, eine andere muß sie als Work-Around so nehmen und in eine Datenbank importieren. Das sind Dateien, die über Millionen von Zeilen verfügen, und die teilweise bis zu 2,5 GB groß werden. Fragt bitte nicht nach dem Sinn oder Unsinn, ich täts auch anders machen, das ist nun mal die Situation. Diese Dateien werden mit einem Datenbankprogramm (genauer SQL Loader von Oracle) in eine entsprechende Datenbank geladen. Sprich, der Loader definiert anhand der Flatfiles eine gewisse Struktur, die dann in die Datenbank importiert wird.

Nun gibt es in diesen Dateien Textfelder, wo die Leute munter einfach Zeilentrenner reinhauen. Ist einerseits verständlich, die haben ihre Masken, und tippen einfach so irgendwelche Texte rein. Da wir keinen Einfluß auf den Export haben, und auch nicht genau wissen, wie diese Daten gewonnen bzw. erzeugt werden, passiert nun folgendes, das in den Flatdateien plötzlich die Datenstrukturen fehlerhaft sind. Feldtrenner ist übrigens TAB \t 0x09, Trenner pro Zeile ist der DOS-Delimiter Carriage Return und Newline \r\n 0d0a

2 Beispieldateien von ca 100 weiteren, Trenner TAB habe ich durch Leerzeichen 0x20 ersetzt:
990 Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
990 Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
990 Feld1 ... Feld21 Feld22 ein Textfeld\r\d
mit falschen\r\d
Umbrüchen und einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
990 Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
000000nnnnnnn Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
Feld1 ... Feld21 Feld22 ein Textfeld\r\d
mit falschen\r\d
Umbrüchen und einigen Inhalten sogar
07:00 Datumsfelder.. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
990 Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d

oder
000000nnnnnnn Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
000000nnnnnnn Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
000000nnnnnnn Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
[B]000000nnnnnnn Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
Feld1 ... Feld21 Feld22 ein Textfeld\r\d
mit falschen\r\d
Umbrüchen und einigen Inhalten sogar
07:00 Datumsfelder.. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d
000000nnnnnnn Feld1 ... Feld21 Feld22 ein Textfeld mit einigen Inhalten .. Feld76 Feld77 ein Textfeld mit einigen Inhalten Feld99\r\d

Da die Datenstruktur nun verletzt wird, kommt es beim Loader permanent zu abbrüchen. Ärgerlich, wenn zig Dateien importiert werden und der Import mehrere Stunden dauert. Eigentlich müßten Umbrüche in Texten sauber maskiert bzw. per ESCAPE-Sequenzen gekennzeichnet werden. Darüber brauchen wir nicht weiter diskutieren.

Nun muß ich ja teilweise erst mal den Fehler finden, also suche ich eben die Stellen, wo der Fehler auftaucht, sprich suche mir eine Zeile, die nicht mit 990 am Zeilenanfang beginnt, oder nicht mit 000000 am Zeilenanfang.

Bisher suchte ich nur nach ^[^990]. Damit hat Monger recht, damit findet er nur, was nicht 9 am Zeilenanfang ist, und das Datumsfeld wird per RegExp übersehen.

Wenn ich suche, kann ich mit ^(990) den String 990 am Zeilenanfang korrekt matchen. Und ich möchte nun einfach die Negation matchen.

Für das Problem habe ich schon ein Perl-Script geschrieben. Mir gehts nun darum, die fehlerhaften Zeilen per RegExp zu finden, und da funktioniert bisher nur
^[^-9-9][^9-9][^0-0]
bzw
^[^0-0][^0-0][^0-0][^0-0][^0-0][^0-0]

Update:
Das funktioniert auch
^[^9][^9][^0]
Das matched wiederum nicht
^[^9]{2}[^0]
^[^9]{2,2}[^0]

bzw. es matched im PsPad, aber nicht im UltraEdit als Unix, aber als Perl. :confused:

Monger
2013-12-12, 11:31:35
Okay. Du willst also alle Zeilen die eben nicht am Anfang einen konkreten Zahlencode haben?

Wenn ich das jetzt hier so lokal ausprobiere, dann funktioniert "^(?!990).+$" .

Das Problem ist, dass der Anker "^" bzw. "$" je nach Regex Engine mitunter etwas anders interpretiert wird. In .NET wird z.B. je nach Multiline Modus das entweder als Anfang/Ende des gesamten Strings oder nur als Anfang der Zeile interpretiert.

Ein anderes Problem könnte sein, wie deine Zeilenumbrüche rauskommen. Wenn der Text mit dem falschen Encoding geladen wird, erkennt er die möglicherweise nicht korrekt. Und offenbar ist das ja kein klassischer Windows Zeilenumbruch (\n\r). Aber rein von der Notation her ist der Negative Lookahead schon das was du brauchst.

PHuV
2013-12-12, 11:35:23
Der klassische Umbruch ist immer 0d0a \r\n. ;)

Wenn ich das jetzt hier so lokal ausprobiere, dann funktioniert "^(?!990).+$" .

:up: Klasse, ja das funktioniert und matched.


000000123456 a b c d e f g
000000123456 a b c d e f g
bla blub
000000123456 a b c d e f g
000 bla blub
000000123456 a b c d e f g
0 bla blub
000000123456 a b c d e f g
000000123456 a b c d e f g

Kann sich jeder ja mal gerne daran probieren. Positives Matchen
^(000000)
Und nun die Negation? :confused:
Wunderbar, klappt auch mit ^(?!000000).+$
Vielen Dank Monger.

PHuV
2013-12-12, 11:43:59
Jetzt muß ich doch noch mal blöde Frage, warum funktioniert dann das Matchen nicht mit
^[?!0]{6}
^[^0]{6}

nalye
2013-12-12, 11:50:30
Eventuell kann das Dein RegExp-Interpreter einfach nicht

PHuV
2013-12-12, 11:58:46
UltraEdit kann angeblich Unix und Perl und eine eigene Syntax (kann man einstellen). PSPad sieht stark nach Unix aus.

Monger
2013-12-12, 11:58:53
^[?!0]{6}
Das hier heißt: matche mir die ersten sechs Zeichen die aus einer Kombination aus Fragezeichen, Ausrufezeichen oder einer Null anfangen. Also zum Beispiel
"000?000 Bla bla , bla bla" würde als Match ergeben: "000?00"
In Charakterklassen (also eckige Klammern) sind nur ganz bestimmte Steuerzeichen zugelassen, und die bedeuten oft etwas anderes als außerhalb.

^[^0]{6}
Das hier wiederum heißt: matche mir die ersten sechs Zeichen jedes Strings dessen Zeichen nicht Null sind. Also positiv: "abcd2asefsd sdfls 2355" ergibt: "abcd2a"
Worauf es zum Beispiel dann gar nicht matcht, wäre sowas: "abc0ab".

Vergiss nicht, dass immer nur das gematcht wird was dein Ausdruck umfasst. Du konzentrierst dich sehr auf die Zahl vorne dran, aber eigentlich willst du ja das was hinter der (in dem Fall nicht existenten) Zahl steht. Du brauchst etwas was den Rest der Zeile erfasst, in meinem Beispiel eben .+$ (beliebiges Zeichen bis Ankerpunkt Zeilenende).

PHuV
2013-12-12, 12:03:17
^[^0]{6}
Das hier wiederum heißt: matche mir die ersten sechs Zeichen jedes Strings dessen Zeichen nicht Null sind.
Und die am Zeilenanfang sind. Aber das ist genau das, was ich will.

Vergiss nicht, dass immer nur das gematcht wird was dein Ausdruck umfasst. Du konzentrierst dich sehr auf die Zahl vorne dran, aber eigentlich willst du ja das was hinter der (in dem Fall nicht existenten) Zahl steht.
An sich interessiert mich wirklich nur der Zeilenanfang, und der Rest nicht.

Monger
2013-12-12, 12:07:28
Und die am Zeilenanfang sind. Aber das ist genau das, was ich will.
Das matcht aber bereits nicht, wenn auch nur irgendeines dieser sechs Zeichen eine Null ist.

PHuV
2013-12-12, 12:13:22
Fuuu, und wie würde ich es denn dann sauber mit Wiederholungsangabe ausdrücken?

Monger
2013-12-12, 12:52:19
Erstmal der Positivfall: "000000" matcht logischerweise auf sechs Nullen. Mit Wiederholungsschreibweise: "0{6}".

Eine invertierte Charakterklasse ist eben keine negative Bedingung. [^0]{2} ist eben zu lesen wie [^0][^0] und nicht etwa [(^0^0)].

Der Negativfall geht halt nur mit den Lookarounds. Du musst ja quasi erstmal nach vorne bis zum siebten Zeichen schauen um zu gucken ob du das erste überhaupt capturen darfst.

PHuV
2013-12-12, 12:59:08
Der Negativfall geht halt nur mit den Lookarounds. Du musst ja quasi erstmal nach vorne bis zum siebten Zeichen schauen um zu gucken ob du das erste überhaupt capturen darfst.
Ok, das verstehe ich. Vielen Dank für die Erklärung.