Czy istnieje sposób w C #, aby sprawdzić, czy ciąg jest zakodowany w Base 64, inny niż tylko próba przekonwertowania go i sprawdzenie, czy wystąpił błąd? Mam taki kod:
// Convert base64-encoded hash value into a byte array.
byte[] HashBytes = Convert.FromBase64String(Value);
Chcę uniknąć wyjątku „Nieprawidłowy znak w ciągu Base-64”, który ma miejsce, jeśli wartość nie jest prawidłowym ciągiem bazowym 64. Chcę po prostu sprawdzić i zwrócić false zamiast obsługiwać wyjątek, ponieważ oczekuję, że czasami ta wartość nie będzie ciągiem bazowym 64. Czy istnieje sposób na sprawdzenie przed użyciem funkcji Convert.FromBase64String?
Dzięki!
Aktualizacja:
Dziękuję za wszystkie odpowiedzi. Oto metoda rozszerzenia, z której wszyscy do tej pory korzystali, wydaje się, że zapewnia ona, że łańcuch przejdzie Convert.FromBase64String bez wyjątku. NET wydaje się ignorować wszystkie końcowe i końcowe spacje podczas konwersji do bazy 64, więc „1234” jest poprawne, podobnie jak „1234”
public static bool IsBase64String(this string s)
{
s = s.Trim();
return (s.Length % 4 == 0) && Regex.IsMatch(s, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None);
}
Dla tych, którzy zastanawiają się nad wydajnością testowania w porównaniu z przechwytywaniem i wyjątkami, w większości przypadków dla tej podstawowej 64 rzeczy szybsze jest sprawdzenie niż złapanie wyjątku, dopóki nie osiągniesz określonej długości. Im mniejsza długość, tym szybciej
W moich bardzo nienaukowych testach: dla 10000 iteracji dla długości znaków 100 000 - 110000 testowanie w pierwszej kolejności było 2,7 razy szybsze.
Dla 1000 iteracji dla znaków o długości od 1 do 16 znaków w sumie dla 16 000 testów było 10,9 razy szybciej.
Jestem pewien, że jest moment, w którym lepiej jest testować przy użyciu metody opartej na wyjątkach. Po prostu nie wiem, w którym momencie to jest.
źródło
=
znaku. Jeśli wypełnienie jest nieprawidłowe, spowoduje to błąd, nawet jeśli dane wejściowe są zgodne z wyrażeniem.\n\fLE16
- Twoja metoda przyniosłaby fałszywie dodatni wynik. Dla każdego, kto czyta i szuka niezawodnej metody; Poleciłbym złapanie FormatException lub użycie RegEx dopasowanego do specyfikacji, zobacz stackoverflow.com/questions/475074/… .@"^[a-zA-Z0-9\+/]*={0,2}$"
Odpowiedzi:
Łatwo jest rozpoznać ciąg Base64, ponieważ będzie on składał się tylko ze znaków
'A'..'Z', 'a'..'z', '0'..'9', '+', '/'
i często jest dopełniony na końcu maksymalnie trzema znakami „=”, aby długość była wielokrotnością 4. Ale zamiast ich porównywać, „ lepiej byłoby zignorować wyjątek, jeśli taki wystąpi.źródło
Użyj Convert.TryFromBase64String z C # 7.2
źródło
Convert.TryFromBase64String(base64.PadRight(base64.Length / 4 * 4 + (base64.Length % 4 == 0 ? 0 : 4), '='), new Span<byte>(new byte[base64.Length]), out _)
. Dziękuję Ci.Wiem, że powiedziałeś, że nie chcesz złapać wyjątku. Ale ponieważ wyłapywanie wyjątku jest bardziej niezawodne, podam i opublikuję tę odpowiedź.
Aktualizacja: zaktualizowałem stan dzięki oybekowi, aby jeszcze bardziej poprawić niezawodność.
źródło
base64String.Contains
wielokrotne wywoływanie może spowodować słabą wydajność, nawet jeślibase64String
jest to duży ciąg.base64String== null || base64String.Length == 0
zstring.IsNullOrEmpty(base64String)
Uważam, że wyrażenie regularne powinno wyglądać następująco:
Dopasowanie tylko jednego lub dwóch końcowych znaków „=”, a nie trzech.
s
powinien być ciągiem, który zostanie sprawdzony.Regex
jest częściąSystem.Text.RegularExpressions
przestrzeni nazw.źródło
Dlaczego po prostu nie złapać wyjątku i nie zwrócić False?
Pozwala to uniknąć dodatkowego obciążenia w typowym przypadku.
źródło
Ze względu na kompletność chciałbym zapewnić pewną implementację. Ogólnie rzecz biorąc, Regex jest kosztownym podejściem, zwłaszcza jeśli ciąg jest duży (co ma miejsce podczas przesyłania dużych plików). Poniższe podejście próbuje najpierw najszybszych sposobów wykrywania.
EDYTOWAĆ
Zgodnie z sugestią Sama możesz także nieznacznie zmienić kod źródłowy. Zapewnia lepsze podejście do ostatniego etapu testów. Rutyna
można użyć do zastąpienia
if (!Base64Chars.Contains(value[i]))
liniiif (IsInvalid(value[i]))
Kompletny kod źródłowy z ulepszeniami Sama będzie wyglądał tak (usunięto komentarze dla przejrzystości)
źródło
Odpowiedź musi zależeć od użycia ciągu. Istnieje wiele łańcuchów, które mogą być „prawidłowym base64” zgodnie ze składnią sugerowaną przez kilka plakatów, ale mogą one „poprawnie” dekodować, bez wyjątku, do śmieci. Przykład: ciąg 8 znaków
Portland
jest prawidłowym Base64. Jaki jest sens stwierdzenia, że jest to poprawny Base64? Myślę, że w pewnym momencie chciałbyś wiedzieć, że ten ciąg powinien lub nie powinien być dekodowany w Base64.W moim przypadku mam ciągi połączeń Oracle, które mogą być zwykłym tekstem, na przykład:
lub w base64 jak
Muszę tylko sprawdzić obecność średnika, ponieważ to dowodzi, że NIE jest to base64, co jest oczywiście szybsze niż jakakolwiek powyższa metoda.
źródło
Knibb High Zasady piłki nożnej!
Powinno to być stosunkowo szybkie i dokładne, ale przyznaję, że nie przeszedłem dokładnego testu, tylko kilka.
Pozwala uniknąć kosztownych wyjątków, regex, a także unika pętli przez zestaw znaków, zamiast tego używa zakresów ascii do walidacji.
źródło
źródło
Będę używać w ten sposób, aby nie musieć ponownie wywoływać metody konwersji
źródło
Dekoduj, ponownie zakoduj i porównaj wynik z oryginalnym ciągiem
źródło
Imho, to naprawdę nie jest możliwe. Wszystkie opublikowane rozwiązania kończą się niepowodzeniem w przypadku ciągów typu „test” i tak dalej. Jeśli można je podzielić przez 4, nie są puste ani puste i jeśli są prawidłowymi znakami base64, przejdą wszystkie testy. To może być wiele strun ...
Nie ma więc prawdziwego rozwiązania poza wiedzą, że jest to ciąg zakodowany w oparciu o 64 . Oto co wymyśliłem:
Spodziewam się, że dekodowany ciąg zaczyna się od określonej struktury, więc sprawdzam to.
źródło
Pewnie. Wystarczy upewnić się, że każda postać jest w zasięgu
a-z
,A-Z
,0-9
,/
, lub+
, a końce ciąg z==
. (Przynajmniej jest to najczęstsza implementacja Base64. Możesz znaleźć implementacje, które używają znaków innych niż ostatnie dwa znaki/
lub+
dla nich).źródło
Tak, ponieważ Base64 koduje dane binarne w ciągi ASCII przy użyciu ograniczonego zestawu znaków, możesz to po prostu sprawdzić za pomocą tego wyrażenia regularnego:
/ ^ [A-Za-z0-9 \ = \ + \ / \ s \ n] + $ / s
co zapewni, że łańcuch zawiera tylko AZ, az, 0-9, „+”, „/”, „=” i białe znaki.
źródło
=
znaku na końcu. Jeśli to dopełnienie jest nieprawidłowe, nie jest to poprawne kodowanie base64, mimo że pasuje do Twojego wyrażenia regularnego. Możesz to zademonstrować, znajdując ciąg bazowy 64 z 1 lub 2=
na końcu, usuwając je i próbując go zdekodować.Sugerowałbym utworzenie wyrażenia regularnego do wykonania tej pracy. Będziesz musiał sprawdzić coś takiego: [a-zA-Z0-9 + / =] Będziesz musiał również sprawdzić długość łańcucha. Nie jestem pewien co do tego, ale jestem prawie pewien, że jeśli coś zostanie przycięte (poza wyściółką „=”), to wybuchnie.
Albo jeszcze lepiej, sprawdź to pytanie o przepełnienie stosu
źródło
Właśnie miałem bardzo podobny wymóg, w którym pozwalam użytkownikowi na wykonanie pewnych manipulacji obrazem w
<canvas>
elemencie, a następnie wysyłam uzyskany obraz.toDataURL()
do zaplecza. Chciałem przeprowadzić weryfikację serwera przed zapisaniem obrazu i zaimplementowałemValidationAttribute
użycie części kodu z innych odpowiedzi:Jak widać, oczekuję ciągu typu image / png, który jest wartością domyślną zwracaną
<canvas>
podczas używania.toDataURL()
.źródło
Sprawdź Base64 lub normalny ciąg
public bool IsBase64Encoded (String str)
{
}
źródło
Wszystkie odpowiedzi zostały podzielone na 1 funkcję, która zapewnia w 100%, że jej wyniki będą dokładne.
1) użyj funkcji jak poniżej:
2) Poniżej znajduje się funkcja:
źródło
Podoba mi się pomysł sprawdzenia wyrażenia regularnego. Wyrażenia regularne mogą być szybkie i czasami oszczędzać narzuty związane z kodowaniem. pierwotne zapytanie miało aktualizację, która właśnie to zrobiła. Uważam jednak, że nigdy nie mogę założyć, że łańcuchy nie będą zerowe. Rozwinąłbym funkcję rozszerzenia, aby sprawdzić ciąg źródłowy pod kątem null lub białych znaków.
źródło