Ist es möglich, ein RegEx zu verwenden, um Base64-Daten zu validieren oder zu bereinigen? Das ist die einfache Frage, aber die Faktoren, die diese Frage antreiben, machen sie schwierig.
Ich habe einen Base64-Decoder, der sich nicht vollständig darauf verlassen kann, dass die Eingabedaten den RFC-Spezifikationen entsprechen. Die Probleme, mit denen ich konfrontiert bin, sind also Probleme wie z. B. Base64-Daten, die möglicherweise nicht in 78 (ich glaube, es sind 78, ich müsste den RFC noch einmal überprüfen, also bitte nicht meckern, wenn die genaue Zahl falsch ist) Zeichenzeilen aufgeteilt sind, oder dass die Zeilen möglicherweise nicht mit CRLF enden, sondern nur ein CR oder LF oder vielleicht keines von beiden enthalten.
Ich hatte also verdammt viel Mühe mit dem Parsen von Base64-Daten, die als solche formatiert sind. Aus diesem Grund sind Beispiele wie die folgenden nicht mehr zuverlässig zu entschlüsseln. Der Kürze halber werde ich nur einen Teil der MIME-Header anzeigen.
Content-Transfer-Encoding: base64
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
Das zu analysieren ist also kein Problem und entspricht genau dem Ergebnis, das wir erwarten würden. Und in 99 % der Fälle funktioniert die Verwendung eines Codes, der zumindest überprüft, ob jedes Zeichen im Puffer ein gültiges base64-Zeichen ist, perfekt. Aber das nächste Beispiel wirft einen Schraubenschlüssel in den Mix.
Content-Transfer-Encoding: base64
http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
Dies ist eine Version der Base64-Kodierung, die ich in einigen Viren und anderen Dingen gesehen habe, die versuchen, den Wunsch einiger E-Mail-Leser auszunutzen, Mime um jeden Preis zu parsen, im Gegensatz zu denen, die sich strikt an das Buch oder besser gesagt RFC halten.
Mein Base64-Decoder dekodiert das zweite Beispiel in den folgenden Datenstrom. Und denken Sie daran, dass der ursprüngliche Datenstrom ausschließlich aus ASCII-Daten besteht!
[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8
Hat jemand eine gute Idee, wie man beide Probleme auf einmal lösen kann? Ich bin mir nicht sicher, ob es überhaupt möglich ist, abgesehen davon, dass man zwei Transformationen mit unterschiedlichen Regeln auf die Daten anwenden und die Ergebnisse vergleichen kann. Aber wenn Sie diesen Ansatz wählen, welchem Ergebnis vertrauen Sie dann? Es scheint, dass die ASCII-Heuristik etwa die am besten Lösung, aber wie viel mehr Code, Ausführungszeit und Komplexität würde das zu etwas so Kompliziertem wie einem Virenscanner hinzufügen, an dem dieser Code tatsächlich beteiligt ist? Wie würden Sie die Heuristik trainieren, damit sie lernt, was für Base64 akzeptabel ist und was nicht?
UPDATE:
Da diese Frage immer wieder gestellt wird, habe ich beschlossen, das einfache RegEx zu veröffentlichen, das ich seit 3 Jahren in einer C#-Anwendung mit Hunderttausenden von Transaktionen verwende. Ehrlich gesagt, gefällt mir die Antwort von Gumbo die beste, weshalb ich sie auch als Antwort ausgewählt habe. Aber jeder mit C#, und auf der Suche nach einer sehr schnellen Weg, um zumindest zu erkennen, ob eine Zeichenfolge oder byte[] enthält gültige Base64-Daten oder nicht, ich habe die folgenden sehr gut für mich arbeiten gefunden.
[^-A-Za-z0-9+/=]|=[^=]|={3,}$
Und ja, das ist nur für eine STRING von Base64-Daten, NICHT eine richtig formatierte RFC1341 Nachricht. Wenn Sie also mit Daten dieses Typs zu tun haben, sollten Sie dies berücksichtigen, bevor Sie versuchen, das obige RegEx zu verwenden. Wenn Sie mit Base16, Base32, Radix oder sogar Base64 für andere Zwecke arbeiten (URLs, Dateinamen, XML-Kodierung usw.), dann ist es sehr empfehlen, dass Sie lesen RFC4648 dass Gumbo in seiner Antwort erwähnt, da Sie sich über den Zeichensatz und die Terminatoren, die von der Implementierung verwendet werden, im Klaren sein müssen, bevor Sie versuchen, die Vorschläge in diesem Frage/Antwort-Set zu verwenden.
0 Stimmen
Ich denke, dass man die Aufgabe besser definieren muss. Es ist völlig unklar, was Ihr Ziel ist: streng sein? 100% der Proben analysieren? ...
0 Stimmen
Ihr erstes Beispiel sollte 'VGhpcyBpcyBhIHNpbXBsZSBBU0NJSSBCYXNlNjQgZXhhbXBsZSBmb3IgU3RhY2tPdmVyZmxvdy4=' lauten.
1 Stimmen
Warum verwenden Sie nicht eine Standardlösung in Ihrer Sprache? Warum brauchen Sie einen handgeschriebenen Parser auf der Grundlage von Regexen?
0 Stimmen
@JF - Nun, ich weiß es nicht. Ich habe mir andere Methoden angesehen und hatte nicht viel Glück, also dachte ich, ich versuche es mal mit RegEx. Das ist alles C/C++, falls das eine Rolle spielt. Und ich mache bereits das Pre-Parsing von ALLEM, was nicht b64 ist, werfe es weg und dekodiere den Rest.
0 Stimmen
@ADEpt - Ziel ist es, 100 % der Zeit parsen zu können, unabhängig davon, wie schlecht formatiert oder beschädigt die Quelle ist. (Ich habe Veranstaltung delt mit Viren, die zufällige BINARY Daten innerhalb der b64-Daten setzen)...
0 Stimmen
Wie kann ich Nicht-Base64-Zeichen durch leere Zeichenfolgen ersetzen?
0 Stimmen
@Sapphire - Das kommt darauf an. Was Sie fragen, ist eine ganz neue Frage wert. Meines Erachtens gibt es drei Möglichkeiten, wie man es machen kann. 1) Fressen Sie die schlechten Zeichen während der Dekodierung. 2) Verwenden Sie eine RegEx-Ersetzung, um alle nicht-Base64-Zeichen durch "" zu ersetzen, oder 3) Verwenden Sie eine Funktion im Code, um Ihren Puffer zu durchlaufen und jedes Zeichen mit einer Base64-Tabelle zu vergleichen, und wenn das Zeichen nicht vorhanden ist, ersetzen Sie die Instanz einfach durch char(32) oder " "... Kontaktieren Sie mich außerhalb von SO, und ich würde mich freuen, einige C-Codes zu teilen, um zu tun, was Sie zu tun versuchen.
0 Stimmen
Hinweis: Nach RFC 2045 wird die neue Zeile nach 76 Zeichen hinzugefügt: "Der kodierte Ausgabestrom muss in Zeilen von jeweils nicht mehr als 76 Zeichen dargestellt werden. Alle Zeilenumbrüche oder andere Zeichen, die nicht im Base64-Alphabet vorkommen, müssen von der Dekodierungssoftware ignoriert werden".
1 Stimmen
Gute Frage. Ich habe zwar die アップデイト Regex mit einem von NPM zurückgegebenen base64-kodierten SHA abgleichen und es scheiterte während die Regex in der ausgewählten Antwort funktioniert einwandfrei .
6 Stimmen
Nicht sicher, wie die アップデイト regex wird immer noch ohne Korrektur veröffentlicht, aber es sieht so aus, als ob der Autor bedeutete um die
^
außerhalb der Klammern, als Startanker. Eine viel bessere Regex, ohne so kompliziert zu werden wie die akzeptierte Antwort, wäre jedoch^[-A-Za-z0-9+/]*={0,3}$