Obliczanie długości Base64?

Po przeczytaniu Base64 wiki ...

Próbuję rozgryźć Jak działa formuła:

Biorąc pod uwagę łańcuch o długości n, długość base64 będzie wynosić Tutaj wpisz opis obrazka

Czyli: 4*Math.Ceiling(((double)s.Length/3)))

Wiem już, że długość base64 musi być %4==0, aby dekoder wiedział, jaka była oryginalna długość tekstu.

Maksymalna liczba wypełnień dla sekwencji może wynosić = lub ==.

Wiki: Liczba wyjść bajtów na bajt wejściowy wynosi około 4 / 3 (33% overhead)

Pytanie:

Jak czy powyższe informacje rozliczają się z długością wyjścia Tutaj wpisz opis obrazka ?

Author: Royi Namir, 2012-11-14

11 answers

Każdy znak jest używany do reprezentowania 6 bitów (log2(64) = 6).

Dlatego 4 znaki są używane do reprezentowania 4 * 6 = 24 bits = 3 bytes.

Więc potrzebujesz 4*(n/3) znaków do reprezentowania n bajtów, a to musi być zaokrąglone do wielokrotności 4.

Liczba niewykorzystanych znaków wypełnienia wynikająca z zaokrąglenia do wielokrotności 4 będzie oczywiście wynosić 0, 1, 2 lub 3.

 146
Author: Paul R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-10 13:34:04

4 * n / 3 daje długość niepakowaną.

I zaokrąglić do najbliższej wielokrotności 4 dla wypełnienia, a ponieważ 4 jest potęgą 2 może używać bitowych operacji logicznych.

((4 * n / 3) + 3) & ~3
 33
Author: Ren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 12:45:36

Dla odniesienia, wzór długości kodera Base64 jest następujący:

Formuła długości kodera Base64

Jak powiedziałeś, koder Base64 podany n bajtów danych wytworzy ciąg znaków 4n/3 Base64. Innymi słowy, co 3 bajty danych będą skutkować 4 znakami Base64. edytuj: w komentarzu poprawnie zaznaczam, że moja poprzednia grafika nie uwzględniała paddingu; prawidłowa formuła jest Ceiling(4n/3).

Artykuł w Wikipedii pokazuje dokładnie jak łańcuch ASCII Man zakodowany w łańcuchu Base64 TWFu w swoim przykładzie. Łańcuch wejściowy ma rozmiar 3 bajtów lub 24 bitów, więc formuła poprawnie przewiduje, że wyjście będzie miało długość 4 bajtów (lub 32 bitów): TWFu. Proces koduje co 6 bitów danych do jednego z 64 znaków Base64, więc 24-bitowe wejście podzielone przez 6 daje 4 znaki Base64.

Pytasz w komentarzu, jaka byłaby wielkość kodowania 123456. Pamiętając, że każda postać tego string ma rozmiar 1 bajtu lub 8 bitów (przy założeniu kodowania ASCII / UTF8), kodujemy 6 bajtów lub 48 bitów danych. Zgodnie z równaniem oczekujemy, że długość wyjściowa wyniesie (6 bytes / 3 bytes) * 4 characters = 8 characters.

Umieszczenie 123456 w koderze Base64 tworzy MTIzNDU2, który ma długość 8 znaków, tak jak oczekiwaliśmy.

 21
Author: David Schwartz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-27 22:51:18

Myślę, że podane odpowiedzi przeoczyły punkt pierwotnego pytania, czyli ile miejsca trzeba przeznaczyć na kodowanie base64 dla danego ciągu binarnego o długości n bajtów.

Odpowiedź brzmi (floor(n / 3) + 1) * 4 + 1

Obejmuje to wypełnienie i kończący znak null. Możesz nie potrzebować wywołania podłogi, jeśli robisz arytmetykę całkowitą.

Łącznie z wypełnieniem, łańcuch base64 wymaga czterech bajtów na każdy trzybajtowy fragment oryginalnego łańcucha, w tym dowolnego częściowego kawałki. Jeden lub dwa bajty dodatkowe na końcu łańcucha nadal będą konwertowane do czterech bajtów w ciągu base64 po dodaniu wypełnienia. Jeśli nie masz bardzo konkretnego zastosowania, najlepiej jest dodać padding, Zwykle znak equals. Dodałem dodatkowy bajt dla znaku null W C, ponieważ łańcuchy ASCII bez tego są trochę niebezpieczne i trzeba będzie nosić długość łańcucha osobno.

 6
Author: Ian Nartowicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-23 15:57:25

Liczby całkowite

Generalnie nie chcemy używać dublerów, ponieważ nie chcemy używać operacji zmiennoprzecinkowych, błędów zaokrąglania itp. Po prostu nie są konieczne.

W tym celu warto pamiętać, jak wykonać podział sufitu: ceil(x / y) w dwójkach można zapisać jako (x + y - 1) / y (unikając liczb ujemnych, ale uważaj na przepełnienie).

Czytelny

Jeśli stawiasz na czytelność, możesz oczywiście zaprogramować ją w ten sposób (przykład w Javie, dla C przydałoby się oczywiście makro):

public static int ceilDiv(int x, int y) {
    return (x + y - 1) / y;
}

public static int paddedBase64(int n) {
    int blocks = ceilDiv(n, 3);
    return blocks * 4;
}

public static int unpaddedBase64(int n) {
    int bits = 8 * n;
    return ceilDiv(bits, 6);
}

// test only
public static void main(String[] args) {
    for (int n = 0; n < 21; n++) {
        System.out.println("Base 64 padded: " + paddedBase64(n));
        System.out.println("Base 64 unpadded: " + unpaddedBase64(n));
    }
}

Inlined

Wyściełane

Wiemy, że potrzebujemy w tym czasie 4 bloków znaków na każde 3 bajty (lub mniej). Zatem wzór staje się (dla x = n I y = 3):

blocks = (bytes + 3 - 1) / 3
chars = blocks * 4

Lub połączone:

chars = ((bytes + 3 - 1) / 3) * 4

Twój kompilator zoptymalizuje 3 - 1, więc zostaw to tak, aby zachować czytelność.

Unpadded

Mniej rozpowszechniony jest wariant nieczytelny, dlatego pamiętamy, że każdy z nich musi mieć znak dla każdego 6 bitów, zaokrąglony w górę:

bits = bytes * 8
chars = (bits + 6 - 1) / 6

Lub połączone:

chars = (bytes * 8 + 6 - 1) / 6

Możemy jednak podzielić przez dwa (jeśli chcemy):

chars = (bytes * 4 + 3 - 1) / 3

Nieczytelne

W przypadku, gdy nie ufasz kompilatorowi, aby zrobił za Ciebie ostateczne optymalizacje (lub jeśli chcesz zmylić swoich kolegów):

Wyściełane

((n + 2) / 3) << 2

Unpadded

((n << 2) | 2) / 3

Oto dwa logiczne sposoby obliczania i nie potrzebujemy żadnych branches, bit-ops lub modulo ops-chyba że naprawdę tego chcemy.

Uwagi:

  • oczywiście może być konieczne dodanie 1 do obliczeń, aby uwzględnić bajt zakończenia null.
  • dla Mime może być konieczne zajęcie się możliwymi znakami zakończenia linii itp. (poszukaj innych odpowiedzi na to pytanie).
 6
Author: Maarten Bodewes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-30 15:52:40

Oto funkcja do obliczania oryginalnego rozmiaru zakodowanego pliku Base 64 jako ciąg znaków w KB:

private Double calcBase64SizeInKBytes(String base64String) {
    Double result = -1.0;
    if(StringUtils.isNotEmpty(base64String)) {
        Integer padding = 0;
        if(base64String.endsWith("==")) {
            padding = 2;
        }
        else {
            if (base64String.endsWith("=")) padding = 1;
        }
        result = (Math.ceil(base64String.length() / 4) * 3 ) - padding;
    }
    return result / 1000;
}
 3
Author: Pedro Silva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-17 09:58:40

Wydaje mi się, że właściwa formuła powinna brzmieć:

n64 = 4 * (n / 3) + (n % 3 != 0 ? 4 : 0)
 2
Author: Valo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-07 00:12:11

Podczas gdy wszyscy debatują nad formułami algebraicznymi, wolałbym po prostu użyć samego BASE64, aby powiedzieć mi:

$ echo "Including padding, a base64 string requires four bytes for every three-byte chunk of the original string, including any partial chunks. One or two bytes extra at the end of the string will still get converted to four bytes in the base64 string when padding is added. Unless you have a very specific use, it is best to add the padding, usually an equals character. I added an extra byte for a null character in C, because ASCII strings without this are a little dangerous and you'd need to carry the string length separately."| wc -c

525

$ echo "Including padding, a base64 string requires four bytes for every three-byte chunk of the original string, including any partial chunks. One or two bytes extra at the end of the string will still get converted to four bytes in the base64 string when padding is added. Unless you have a very specific use, it is best to add the padding, usually an equals character. I added an extra byte for a null character in C, because ASCII strings without this are a little dangerous and you'd need to carry the string length separately." | base64 | wc -c

710

Wydaje się więc, że wzór 3 bajtów reprezentowany przez 4 znaki base64 wydaje się prawidłowy.

 1
Author: Michael Adams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-29 01:12:56

W windows-chciałem oszacować rozmiar bufora wielkości mime64, ale wszystkie precyzyjne formuły obliczeniowe nie działały dla mnie - w końcu skończyłem z przybliżoną formułą taką:

Mine64 string allocation size (approximate) = (((4 *((Rozmiar bufora binarnego) + 1)) / 3) + 1)

Więc last +1-jest używany do ascii-zero-ostatni znak musi być przypisany do przechowywania zakończenia zerowego - ale dlaczego" rozmiar bufora binarnego " to + 1 - podejrzewam, że jest jakiś znak zakończenia mime64 ? A może to jakiś problem z wyrównaniem.

 0
Author: TarmoPikaro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-27 07:48:20

Prosta implementacja w javascript

function sizeOfBase64String(base64String) {
    if (!base64String) return 0;
    const padding = (base64String.match(/(=*)$/) || [])[1].length;
    return 4 * Math.ceil((base64String.length / 3)) - padding;
}
 0
Author: qoomon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-17 11:13:25

Wierzę, że to jest dokładna odpowiedź, jeśli n%3 nie zero, Nie ?

    (n + 3-n%3)
4 * ---------
       3

Wersja Mathematica:

SizeB64[n_] := If[Mod[n, 3] == 0, 4 n/3, 4 (n + 3 - Mod[n, 3])/3]

Baw się dobrze

GI

 -1
Author: igerard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-06 07:28:07