Ist es möglich, mit einem RegEx Base64-Daten zu validieren oder zu bereinigen? Das ist die einfache Frage, aber die Faktoren, die diese Frage antreiben, machen es schwierig.
Ich habe einen Base64-Decoder, der sich nicht vollständig auf die Eingabedaten verlassen kann, um den RFC-Spezifikationen zu folgen. Die Probleme, mit denen ich konfrontiert bin, sind Probleme wie vielleicht Base64-Daten, die möglicherweise nicht in 78 unterteilt sind (ich denke, es ist 78, ich müsste den RFC noch einmal überprüfen, also sag mir nichts, wenn die genaue Zahl falsch ist) Zeilen oder dass die Zeilen möglicherweise nicht in CRLF enden; , dass es nur eine CR oder LF haben kann, oder vielleicht auch keine.
Ich hatte verdammt viel Zeit damit, als solche formatierte Base64-Daten zu analysieren. Aus diesem Grund können Beispiele wie die folgenden nicht mehr zuverlässig dekodiert werden. Der Kürze halber werde ich nur teilweise MIME-Header anzeigen.
Content-Transfer-Encoding: base64
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
Ok, das Parsen ist also kein Problem und genau das Ergebnis, das wir erwarten würden. In 99% der Fälle funktioniert die Verwendung eines beliebigen Codes, um zumindest zu überprüfen, ob jedes Zeichen im Puffer ein gültiges base64-Zeichen ist, einwandfrei. Aber das nächste Beispiel wirft einen Schraubenschlüssel in die Mischung.
Content-Transfer-Encoding: base64
http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
Dies ist eine Version der Base64-Codierung, die ich bei einigen Viren und anderen Dingen gesehen habe, die versuchen, die Vorteile einiger E-Mail-Leser zu nutzen. Sie möchten Mime um jeden Preis analysieren, im Gegensatz zu solchen, die sich strikt an das Buch halten, oder besser gesagt an RFC. wenn man so will.
Mein Base64-Decoder decodiert das zweite Beispiel in den folgenden Datenstrom. Und denken Sie daran, der ursprüngliche Stream besteht aus allen ASCII-Daten!
[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8
Hat jemand eine gute Möglichkeit, beide Probleme gleichzeitig zu lösen? Ich bin mir nicht sicher, ob es überhaupt möglich ist, zwei Transformationen an den Daten mit unterschiedlichen Regeln durchzuführen und die Ergebnisse zu vergleichen. Wenn Sie diesen Ansatz gewählt haben, welchem Output vertrauen Sie? Es scheint, dass ASCII-Heuristiken die beste Lösung sind, aber wie viel mehr Code, Ausführungszeit und Komplexität würde dies zu etwas so Kompliziertem wie einem Virenscanner beitragen, an dem dieser Code tatsächlich beteiligt ist? Wie würden Sie die Heuristik-Engine trainieren, um zu erfahren, was Base64 akzeptabel ist und was nicht?
AKTUALISIEREN:
Angesichts der Anzahl der Aufrufe, die diese Frage weiterhin erhält, habe ich beschlossen, das einfache RegEx, das ich seit 3 Jahren in einer C # -Anwendung verwende, mit Hunderttausenden von Transaktionen zu veröffentlichen. Ehrlich gesagt gefällt mir die Antwort von Gumbo am besten, weshalb ich sie als ausgewählte Antwort ausgewählt habe. Aber für alle, die C # verwenden und nach einer sehr schnellen Möglichkeit suchen, um zumindest festzustellen, ob eine Zeichenfolge oder ein Byte [] gültige Base64-Daten enthält oder nicht, hat sich Folgendes für mich als sehr gut erwiesen.
[^-A-Za-z0-9+/=]|=[^=]|={3,}$
Und ja, dies ist nur für einen STRING von Base64-Daten, NICHT für eine richtig formatierte RFC1341- Nachricht. Wenn Sie also mit Daten dieses Typs arbeiten, berücksichtigen Sie dies bitte, bevor Sie versuchen, das oben genannte RegEx zu verwenden. Wenn Sie sich für andere Zwecke (URLs, Dateinamen, XML-Codierung usw.) mit Base16, Base32, Radix oder sogar Base64 beschäftigen, wird dringend empfohlen, RFC4648 zu lesen , das Gumbo in seiner Antwort erwähnt hat, da Sie gesund sein müssen Beachten Sie den Zeichensatz und die Terminatoren, die von der Implementierung verwendet werden, bevor Sie versuchen, die Vorschläge in diesem Frage- / Antwortsatz zu verwenden.
^
Äußere der Klammern als Startanker zu setzen . Ein viel besserer Regex, ohne so kompliziert zu werden wie die akzeptierte Antwort, wäre jedoch^[-A-Za-z0-9+/]*={0,3}$