Regex
^(?<GUID>\{?[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\}?)(?:\((?<version>\d+)\))?(?:\((?<type>\w+)\))?(?:.jpg)?$
hat ca. 1-2h gedauert, je nachdem, ob ich meine Recherche gestern Abend mitzähle oder nicht. Ist wohl auch noch nicht 100% optimiert, erfüllt aber seinen Zweck zu 100%. Hätte per Hand/zu Fuss ausprogrammiert mit Sicherheit länger gedauert. Unentbehrliches Tool: Espresso! http://www.ultrapico.com/Expresso.htm - Ein gutes Tutorial gibt es auch dazu: http://www.codeproject.com/dotnet/RegexTutorial.asp.
Was das alles soll? - Ich muss einen Request String auseinandernehmen und feststellen, ob er die Daten enthält, die ich erwarte. Wenn ja, soll der String auch gleich so zerlegt werden, dass ich an die einzelnen Parameter leicht herankomme. Ideal dafür ist natürlich die Regex Library, die im .NET Framework eingebaut ist. Allerdings hatte ich mich bei ähnlichen Gelegenheiten zuvor immer gerne gedrückt, weil die Beschäftigung mit Regex immer etwas Hirnschmerz auslöst.
Gesucht werden folgende Muster:
CA8D3EEF-9289-4A39-A1FF-3D3AA57CACC2
ca8d3eef-9289-4a39-a1ff-3d3aa57cacc2(1)
CA8D3EEF-9289-4A39-A1FF-3D3AA57CACC2(2)(Thumbnail)
CA8D3EEF-9289-4A39-A1FF-3D3AA57CACC2.jpg
CA8D3EEF-9289-4A39-A1FF-3D3AA57CACC2(2).jpg
CA8D3EEF-9289-4A39-A1FF-3D3AA57CACC2(1)(Thumbnail).jpg
Nicht ok wären diese hier:
daddeldueh.aspx (ganz weit draussen)
CA8D3EEF-9289-439-A1FF-3D3AA57CACC2 (inkorrekte GUID)
CA8D3EEF-9289-4A39-A1FF-3D3AA57CACC2(A).jpg (falscher Parameter)
Alternative zu Regex wäre eine IndexOf(...) gesteuerte Schleifenkonstruktion gewesen, die aber aufwendig zu programmieren, zu debuggen und vor allem zu warten wäre. Also Regex! - Wenn da nicht der Hirnschmerz wäre...
Was macht das Konstrukt? - In Einzelteilen ist das eigentlich ganz einfach:
| ^ |
Starte immer am Anfang des Strings, nie woanders (d.h. im Wesentlichen, wenn vor dem Match noch andere Zeichen stehen, wie z.B. Leerzeichen oder so, dann ist das ein Fehler) |
| (?<GUID>\{?[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\}?) |
Matche eine GUID und gib sie in einem Feld mit gleichem Namen zurück. Im Einzelnen: |
| (?<GUID>xxx) |
d.h. matche xxx (was immer das dann ist) und gib das Ergebnis als Feld Names GUID zurück. Es muss genau 1 Match da sein (kein ? oder * etc. nach dem letzten ) == genau 1 Match) |
| \{? |
das Zeichen { (delimitiert geschrieben \}, da{} auch in der Regex Syntax genutzt werden), ? besagt 0 oder 1 Mal. D.h. die GUID darf mit { anfangen, muss aber nicht. |
| [\da-f]{8}- |
\d heisst eine beliebige Zahl, a-f heisst ein beliebiger Buchstabe zwischen a und f, die [...] heissen, dass der Match aus diesem Bereich kommen muss (d.h. entweder Zahl oder a,b,c,d,e oder f). Das {8} heisst der Match muss 8 mal zustande kommen und das - ist das Zeichen -, das zwischen den einzelnen Teilen der GUID stehen muss. Entsprechend geht das weiter mit den anderen Blöcken der GUID. |
| \}? |
Abschluss der GUID, optional |
| (?:\((?<version>\d+)\))? |
Finde ein optionales Konstrukt wenn vorhanden, wenn nicht ist auch ok. Das Konstrukt ist eine Zahl mit 1 oder mehr Stellen und soll im Erfolgsfall in das Feld namens Version gespeichert werden. Im Einzelnen: |
| (?:xxx)? |
Eine nicht weiter benannte Gruppe. Das ? besagt, dass sie 0 oder 1 Mal da sein darf. Die Gruppe soll xxx matchen, was immer das ist. |
| \(? |
ein ( kann optional da sein |
| ((?<version>\d+) |
dann folgt eine Gruppe mit Namen Version, die aus einer Zahl mit 1 oder mehreren Stellen besteht (+). |
| \)? |
dann darf optional ein ) da sein. |
| (?:\((?<type>\w+)\))? |
im Grunde genommen siehe oben. \w bezeichnet ein Wort. Das Konstrukt ist wieder optional. |
| (?:.jpg)? |
eine nicht weiter bezeichnete Gruppe, die auf die Zeichenfolge .jpg matcht. Das Konstrukt ist auch optional. |
| $ |
Ende des Strings. Nach dem letzten Match dürfen keine weiteren Quatschzeichen mehr kommen (mögliche Buffer-Overflow Attacke). |
Damit kann ich jetzt ganz einfach matchen :) - Das sieht dann so oder so ähnlich im Code aus:
string Query = @"^(?<GUID>\{?[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\}?)(?:\((?<Version>\d+)\))?(?:\((?<Type>\w+)\))?(?:\(p(?<Page>\d+)\))?(?:.jpg)?$";
Regex ThisRegex = new Regex( Query, RegexOptions.IgnoreCase );
Match ThisMatch = ThisRegex.Match( RequestedName );
if( ThisMatch.Groups["GUID"].Success == true )
{
DocumentID = new Guid( ThisMatch.Groups["GUID"].Value );
}
else
{
return false;}