[C#] Regex Problem

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

[C#] Regex Problem

Beitrag von BeRsErKeR »

Hallo,

hab vor 2 Tagen angefangen C# zu programmieren. Nun spiel ich gerade mit der Regex-Klasse rum und möchte Strings auf eine bestimmte Form prüfen mittels Regex.Match.

Folgendes Pattern nutze ich:

Code: Alles auswählen

@"(+|-)?(0|[1-9]([0-9]){0,19})((d|du|ds|u|s)(8|16|32|64)?)?"
Damit möchte ich dezimale Integerliterale (bzw. deren Stringrepresentation) finden, die optional ein Vorzeichen enthalten und einen optionalen Suffix d, sowie einen der beiden optionalen Suffixe u oder s und einen weiteren optionalen Suffix (8, 16, 32 oder 64), der jedoch nur auf einen der anderen 3 Suffixe folgen darf.

Beispiele:

Code: Alles auswählen

123
-123
+123
123u
123s
123d
123ds
123du
123u32
123d16
-123s64
Leider fliegt mir beim Aufruf von Regex.Match mit diesem Pattern eine Exception um die Ohren, die folgendes sagt:
Quantifizierer {x,y} nach nichts.
Prinzipiell versteh ich die Fehlermeldung, allerdings stehen ja alle 4 Quantifizierer (sowohl die geschweiften Klammern, als auch die 3 Fragezeichen) immer hinter einem Ausdruck.

Kann mir da wer helfen? Die Hilfe sagt auch nur, dass sich Quantifizierer immer auf den Ausdruck der direkt vorangeht beziehen. Aber das ist ja gegeben. Ich seh wahrscheinlich den Wald vor lauter Bäumen nicht.
Ohne Input kein Output.
LaBerg
Beiträge: 22
Registriert: 09.05.2002, 22:53

Re: [C#] Regex Problem

Beitrag von LaBerg »

Die Ursache für die Fehlermeldung ist das '+' ganz am Anfang von deinem Regulären Ausdruck. '+' muss man escapen, da es für "Eins oder Viele" steht.
Ich habe noch ein Zeilen-Anfang bzw. Ende hinzugefügt. Sonst matcht es meiner Ansicht nach zu viel. Aber das hängt ja vom Anwendungsfall ab.

Code: Alles auswählen

@"^(\+|-)?(0|[1-9]([0-9]){0,19})((d|du|ds|u|s)(8|16|32|64)?)?$"
Es gibt ein recht gutes Tool nennt sich 'Expresso', um solche Regulären Ausdrücke für C# zu bauen und zu testen.
http://www.ultrapico.com/ExpressoDownload.htm
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C#] Regex Problem

Beitrag von BeRsErKeR »

Ah ja danke. Hab ich übersehen. Das mit dem Zeilenanfang erzwingt doch, dass es auch dort beginnt oder? Weil in meinem Fall kann das irgendwo in einer Zeile stehen.


Gleich noch eine Frage hintendran. Kann man irgendwie einstellen, dass er das längste Match nimmt, was er findet?

Bislang matched er bei meinem Pattern für Gleitkommaliterale anstatt 0.5f32 nur 0.5f.

Aktuelles Pattern dafür: @"(\+|-)?(0|[1-9][0-9]*)[.][0-9]+(f|f32|f64|f128)?"

Ok bei Dezimalzahlen matched er das längste Vorkommen, daher ist wohl am Pattern was falsch.


Mit folgendem Pattern geht es nun: @"(\+|-)?(0|[1-9][0-9]*)[.][0-9]+(f(32|64|128)?)?"

Ich frage mich nur wieso das obere nicht funktioniert. Liegt es an der Oder-Verknüpfung mit | ?


Ein ähnliches Problem habe ich mit den Suffixkombinationen für dezimale Literale:

@"(\+|-)?(0|[1-9]([0-9]){0,19})((d|du|ds|u|s)(8|16|32|64)?)?"

Hier wird zwar gematched sofern ich nur d, nur u oder nur s als Suffix nutze (die Zahlensuffixe gehen dann auch). Wenn ich aber die Kombinationen du oder ds verwende matched es nicht mehr (bzw. nur bis zum d). Bei oktalen Literalen wie im Folgenden gezeigt funktioniert es hingegen, da der Suffix o dort Pflicht ist und ich deshalb ein etwas anderes Pattern nutze:

@"(([1-7]([0-7]){0,20})|(1([0-7]){1,21})|0)o(u|s)?(8|16|32|64)?"


Beispiele zur Veranschaulichung:

Code: Alles auswählen

// Dezimalliterale
123ds64 // 123 als vorzeichenbehafteter 64Bit Dezimalwert
5u8 // 5 als vorzeichenloser 8Bit Dezimalwert
0d // 0 als Dezimalwert
17u // 17 als vorzeichenloser Dezimalwert
500 // 500 als Dezimalwert

// Oktalliterale
17ou32 // 17 als vorzeichenloser 32Bit Oktalwert
1337o16 // 1337 als 16Bit Oktalwert
0o // 0 als Oktalwert
// aber nicht 17u da das Suffix o Pflicht ist, 17u würde als Dezimalliteral identifiziert werden
Ohne Input kein Output.
LaBerg
Beiträge: 22
Registriert: 09.05.2002, 22:53

Re: [C#] Regex Problem

Beitrag von LaBerg »

Ok dann vergiss das mit dem Zeilenanfang bzw. Zeilenende. Bringt in deinem Fall nichts.

bei diesem hier:

Code: Alles auswählen

@"(\+|-)?(0|[1-9]([0-9]){0,19})((d|du|ds|u|s)(8|16|32|64)?)?"
ist das Problem, dass sobald ein 'd' gefunden wird dieser Teil der Bedingung erfüllt ist und versucht wird ein Match auf den nächsten Teil zu finden. Also die 8, 16 etc. Das wird bei 'du' jedoch nicht passen denn das nächste Zeichen nach dem 'd' ist nunmal ein 'u'.

In deinem Fall reicht es einfach die Reihenfolge in dem Oder umzustellen:

Code: Alles auswählen

@"(\+|-)?(0|[1-9]([0-9]){0,19})((du|ds|d|u|s)(8|16|32|64)?)?"
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C#] Regex Problem

Beitrag von BeRsErKeR »

Vielen Dank. Klappt super. ;)
Ohne Input kein Output.
jumphigh
Beiträge: 19
Registriert: 30.06.2004, 13:41
Kontaktdaten:

Re: [C#] Regex Problem

Beitrag von jumphigh »

Warum überhaupt soviel Auswahl? Wenn, dann nur ((du|ds)(8|16|32|64))?, alles andere halte ich für fragwürdig, weil nicht stringent. Und wofür benötigt man überhaupt die Größenangaben, sollte das nicht Bestandteil der Variablendeklaration sein, statt in einem Literal kodiert zu werden?

MfG
Andreas
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C#] Regex Problem

Beitrag von BeRsErKeR »

Naja wenn man an Template-Funktionen denkt, und implizite Erkennung realisieren will, dann macht das schon Sinn.

100du32 wird dann halt als unsigned int32 interpretiert und so z.B. die entsprechende Template-Funktion aufgerufen. Hätte man als mögliches Literal z.B. nur 100 oder 100u zur Verfügung, so hätte man wenig Kontrolle bzw kann nur die int- bzw. unsigned int-Version aufrufen ohne vorher was temporäres anzulegen oder explizit zu casten.

Das d ist in diesem Fall deshalb optional, weil es mühsam ist für jede Zahl im Code ein Suffix anzuhängen. In der Regel arbeitet man halt mit dezimalen Zahlen. Gleiches gilt für u und s. Fehlt dieses Suffix entscheidet der Compiler was am besten passt. Manchmal möchte man aber explizit einen speziellen Typ als Integral angeben.

u und s ohne Zahl soll auch möglich sein, weil man manchmal nur angeben will ob der Typ ein Vorzeichen haben kann und es nicht wichtig ist wie groß der Wert ist.


Beispiele (in C++ Code):

Code: Alles auswählen

template <typename T>
bool WriteToFile(const std::string &filename, T value)
{
// open a file
// write value to file
// close file
}

WriteToFile(50u8); // 50 als 8-Bit-Wert schreiben
WriteToFile(50u32); // 50 als 32-Bit-Wert schreiben

template <typename T>
bool IsNegative(T value) const
{
return value < 0;
}

template <>
bool IsNegative(unsigned int value) const
{
return false;
}

if (IsNegative(100))
// don't think so

if (IsNegative(-100))
// should be

if (IsNegative(100u))
// nope

if (IsNegative(-100u))
// compile error
Ohne Input kein Output.
Antworten