Base64 लंबाई गणना?


155

बेस 64 विकी पढ़ने के बाद ...

मैं यह जानने की कोशिश कर रहा हूं कि फार्मूला कैसे काम कर रहा है:

की लंबाई के साथ एक स्ट्रिंग को देखते हुए n, बेस 64 की लंबाई होगीयहाँ छवि विवरण दर्ज करें

जो है : 4*Math.Ceiling(((double)s.Length/3)))

मुझे पहले से ही पता है कि बेस 64 की लंबाई %4==0डिकोडर को यह जानने की अनुमति होनी चाहिए कि मूल पाठ की लंबाई क्या थी।

एक अनुक्रम के लिए पैडिंग की अधिकतम संख्या =या हो सकती है ==

विकी: इनपुट बाइट प्रति आउटपुट बाइट्स की संख्या लगभग 4/3 (33% ओवरहेड) है

सवाल:

उपरोक्त जानकारी आउटपुट लंबाई के साथ कैसे तय होती है यहाँ छवि विवरण दर्ज करें?

जवाबों:


210

प्रत्येक वर्ण का उपयोग 6 बिट्स ( log2(64) = 6) को दर्शाने के लिए किया जाता है ।

इसलिए 4 वर्णों का प्रतिनिधित्व करने के लिए उपयोग किया जाता है 4 * 6 = 24 bits = 3 bytes

तो आपको बाइट्स 4*(n/3)का प्रतिनिधित्व करने के लिए चार्ट की आवश्यकता nहोती है, और इसे 4 के कई तक गोल करना पड़ता है।

4 के कई तक गोलाई से उत्पन्न अप्रयुक्त गद्दी वर्णों की संख्या स्पष्ट रूप से 0, 1, 2 या 3 होगी।


यहाँ पैडिंग कहाँ है?
रॉय नमिर

1
विचार करें कि क्या आपके पास इनपुट का एक बाइट है। यह आउटपुट के चार वर्णों का उत्पादन करेगा। लेकिन इनपुट को एन्कोड करने के लिए केवल दो आउटपुट कैरेक्टर की जरूरत होती है। तो दो किरदार पैडिंग होंगे।
डेविड श्वार्ट्ज

2
आउटपुट लंबाई हमेशा 4 के कई तक गोल होती है, इसलिए 1, 2 या 3 इनपुट बाइट्स => 4 चार्ट; 4, 5 या 6 इनपुट बाइट्स => 8 वर्ण; 7, 8 या 9 इनपुट बाइट्स => 12 वर्ण।
पॉल आर

5
मैंने ऊपर दिए गए उत्तर में यह सब समझाया: (i) प्रत्येक आउटपुट चार इनपुट के 6 बिट्स का प्रतिनिधित्व करता है , (ii) 4 आउटपुट चार्ट इसलिए 4 * 6 = 24 बिट्स का प्रतिनिधित्व करते हैं , (iii) 24 बिट्स 3 बाइट्स हैं , (iv) 3 बाइट्स इसलिए इनपुट का परिणाम 4 वर्णों में होता है, (v) इनपुट बाइट्स के लिए आउटपुट वर्णों का अनुपात इसलिए 4/3 होता है
पॉल आर

2
@ Techie_28: मैं इसे 20 * 1024 बाइट्स के लिए 27308 अक्षर बनाता हूं, लेकिन मैंने आज सुबह कॉफी नहीं पी है।
पॉल आर।

60

4 * n / 3 अनपेड लंबाई देता है।

और पैडिंग के लिए सबसे पास के 4 के लिए गोल, और 4 के रूप में 2 की एक शक्ति है जो बिटवाइज़ लॉजिकल ऑपरेशंस का उपयोग कर सकती है।

((4 * n / 3) + 3) & ~3

1
तुम सही हो! -> 4 * n / 3 अनपेड लंबाई देता है! ऊपर दिए गए उत्तर सही नहीं हैं। -> ((4 * n / 3) + 3) और ~ 3 सही परिणाम देता है
Cadburry

विंडो के API CryptBinaryToStringA के लिए इनपुट के रूप में काम नहीं करता है।
TarmoPikaro

शेल का उपयोग करने वाले लोगों के लिए इसे वर्तनी के लिए:$(( ((4 * n / 3) + 3) & ~3 ))
स्टारफ्री

1
4 * n / 3पहले से ही विफल रहता है n = 1, एक बाइट दो वर्णों का उपयोग कर एन्कोडेड है, और परिणाम स्पष्ट रूप से एक वर्ण है।
मार्टन बोडेव्स

1
@ क्रॉग जैसा कि नीचे लिखा गया है यदि n = 1 है तो आपको पूर्णांक का उपयोग करके 4/3 = 1 मिलेगा। जैसा कि आपने संकेत दिया है, अपेक्षित परिणाम 2 है, न कि 1.
Maarten Bodewes

25

संदर्भ के लिए, बेस 64 एनकोडर की लंबाई सूत्र निम्नानुसार है:

बेस 64 एनकोडर की लंबाई का सूत्र

जैसा कि आपने कहा, nडेटा के बाइट्स द्वारा दिया गया एक बेस 64 एनकोडर 4n/3बेस 64 अक्षरों की एक स्ट्रिंग उत्पन्न करेगा । एक और तरीका रखो, हर 3 बाइट डेटा में 4 बेस 64 अक्षर होंगे। संपादित करें : एक टिप्पणी सही ढंग से बताती है कि मेरे पिछले ग्राफिक ने पैडिंग का हिसाब नहीं दिया था; सही सूत्र है Ceiling(4n/3)

विकिपीडिया लेख बिल्कुल दिखाता है कि कैसे ASCII Man स्ट्रिंग TWFuने अपने उदाहरण में Base64 स्ट्रिंग में एन्कोड किया । इनपुट स्ट्रिंग आकार में 3 बाइट्स, या 24 बिट्स है, इसलिए सूत्र सही ढंग से भविष्यवाणी करता है कि आउटपुट 4 बाइट्स (या 32 बिट्स) लंबा होगा:TWFu :। प्रक्रिया 64 बेस 64 अक्षरों में से प्रत्येक में 6 बिट डेटा को एनकोड करती है, इसलिए 24 बिट इनपुट को 4 टीएचएल वर्णों में 6 परिणामों से विभाजित किया जाता है।

आप एक टिप्पणी में पूछते हैं कि एन्कोडिंग का आकार क्या 123456होगा। यह ध्यान में रखते हुए कि उस स्ट्रिंग का प्रत्येक वर्ण 1 बाइट या 8 बिट है, आकार में (ASCII / UTF8 एन्कोडिंग मानकर), हम 6 बाइट्स, या 48 बिट्स, डेटा का एन्कोडिंग कर रहे हैं। समीकरण के अनुसार, हमें उम्मीद है कि आउटपुट की लंबाई होगी (6 bytes / 3 bytes) * 4 characters = 8 characters

123456बेस 64 एनकोडर में डालने MTIzNDU2से 8 अक्षर लंबे होते हैं, जैसा कि हमें उम्मीद थी।


5
इस सूत्र का उपयोग करते हुए, ध्यान रखें कि यह गद्देदार लंबाई नहीं देता है। तो आपकी लंबाई लंबी हो सकती है।
स्पिलरिक्स

बेस 64 टेक्स्ट से अपेक्षित डीकोड किए गए बाइट्स की गणना करने के लिए, मैं सूत्र का उपयोग करता हूं floor((3 * (length - padding)) / 4)। निम्नलिखित gist की जाँच करें ।
कर्ट वंगराफशेपे

13

पूर्णांकों

आम तौर पर हम डबल्स का उपयोग नहीं करना चाहते हैं क्योंकि हम फ्लोटिंग पॉइंट ऑप्स, राउंडिंग एरर आदि का उपयोग नहीं करना चाहते हैं। वे अभी जरूरी नहीं हैं।

इसके लिए यह याद रखना एक अच्छा विचार है कि छत के विभाजन को कैसे किया जाए: ceil(x / y)डबल्स में लिखा जा सकता है (x + y - 1) / y(नकारात्मक संख्या से बचने के दौरान, लेकिन अतिप्रवाह से सावधान रहें)।

पठनीय

यदि आप पठनीयता के लिए जाते हैं, तो आप निश्चित रूप से इसे भी इस तरह से प्रोग्राम कर सकते हैं (उदाहरण के लिए जावा में, सी के लिए आप मैक्रो का उपयोग कर सकते हैं, बेशक):

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

गुदगुदा

हम जानते हैं कि हमें प्रत्येक 3 बाइट्स (या कम) के लिए 4 वर्ण ब्लॉक की आवश्यकता है। तो फिर सूत्र बन जाता है (x = n और y = 3 के लिए):

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

या संयुक्त:

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

आपका कंपाइलर ऑप्टिमाइज़ करेगा 3 - 1, इसलिए पठनीयता बनाए रखने के लिए इसे ऐसे ही छोड़ दें।

unpadded

कम आम अनपेड वैरिएंट है, इसके लिए हमें याद है कि प्रत्येक को हमें प्रत्येक 6 बिट्स के लिए एक चरित्र की आवश्यकता होती है, गोल:

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

या संयुक्त:

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

हम अभी भी दो से विभाजित कर सकते हैं (यदि हम चाहते हैं):

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

अस्पष्ट

यदि आप अपने कंपाइलर पर भरोसा नहीं करते हैं तो आपके लिए अंतिम अनुकूलन (या यदि आप अपने सहयोगियों को भ्रमित करना चाहते हैं):

गुदगुदा

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

unpadded

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

इसलिए, हम गणना के दो तार्किक तरीके हैं, और हमें किसी भी शाखा, बिट-ऑप्स या मोडुलो ऑप्स की आवश्यकता नहीं है - जब तक कि हम वास्तव में नहीं चाहते हैं।

टिप्पणियाँ:

  • जाहिर है आपको एक शून्य समाप्ति बाइट को शामिल करने के लिए गणना में 1 जोड़ने की आवश्यकता हो सकती है।
  • माइम के लिए आपको संभावित लाइन समाप्ति पात्रों और इस तरह की देखभाल करने की आवश्यकता हो सकती है (इसके लिए अन्य उत्तरों की तलाश करें)।

5

मुझे लगता है कि दिए गए उत्तर मूल प्रश्न के बिंदु को याद करते हैं, जो कि लंबाई n बाइट्स के दिए गए बाइनरी स्ट्रिंग के लिए बेस 64 एन्कोडिंग को फिट करने के लिए कितनी जगह आवंटित करने की आवश्यकता है।

उत्तर है (floor(n / 3) + 1) * 4 + 1

इसमें पैडिंग और एक समाप्ति अशक्त चरित्र शामिल हैं। यदि आप पूर्णांक अंकगणित कर रहे हैं तो आपको फ्लोर कॉल की आवश्यकता नहीं हो सकती है।

पैडिंग सहित, बेस 64 स्ट्रिंग को मूल स्ट्रिंग के प्रत्येक तीन-बाइट चंक के लिए चार बाइट्स की आवश्यकता होती है, जिसमें कोई भी आंशिक हिस्सा शामिल है। स्ट्रिंग के अंत में एक या दो बाइट्स अतिरिक्त तब भी आधार64 स्ट्रिंग में चार बाइट्स में परिवर्तित हो जाएंगे जब पैडिंग जोड़ा जाता है। जब तक आपके पास एक बहुत विशिष्ट उपयोग नहीं है, तब तक पैडिंग को जोड़ना सबसे अच्छा है, आमतौर पर एक समान चरित्र। मैंने C में एक अशक्त चरित्र के लिए एक अतिरिक्त बाइट जोड़ा, क्योंकि इसके बिना ASCII तार थोड़े खतरनाक हैं और आपको अलग से स्ट्रिंग की लंबाई ले जाने की आवश्यकता होगी।


5
आपका सूत्र गलत है। N = 3 पर विचार करें, अपेक्षित परिणाम (शून्य गद्दी के बिना) 4 है, लेकिन आपका सूत्र 8. लौटाता है
कोड्सचैडोस

5
मुझे भी लगता है कि शून्य टर्मिनेटर भी मूर्खतापूर्ण है, खासकर जब से हम यहाँ .net के बारे में बात कर रहे हैं।
कोडइन्चौस

CryptBinaryToStringA का उपयोग करके विंडोज़ में सही ढंग से काम करता है। इसके लिए मेरा वोट।
TarmoPikaro

5

यहाँ एक एनकोडेड बेस 64 फ़ाइल के मूल आकार की गणना 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

जबकि बाकी सभी लोग बीजीय सूत्रों पर बहस कर रहे हैं, मैं केवल BASE64 का उपयोग खुद को बताने के लिए करूँगा:

$ 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

तो ऐसा लगता है कि 4 बेस 64 अक्षरों द्वारा दर्शाए जा रहे 3 बाइट्स का सूत्र सही लगता है।


1
मुझे गणनाओं के खिलाफ कुछ मिला है जिसमें बहुत अधिक मेमोरी और सीपीयू समय की आवश्यकता होती है, जबकि गणना 1 एनएस और एक या दो रजिस्टरों में की जा सकती है।
मार्टन बॉड्यूज

तो जब आप अज्ञात मात्रा में द्विआधारी डेटा से निपटने की कोशिश कर रहे हैं - यह कैसे मदद करता है?
UKMonkey

प्रश्न सभी फ़ार्मुलों के बारे में है, जो बेस 64 को किए बिना आउटपुट आकार की गणना करने में मदद करते हैं। हालांकि यह उत्तर कुछ स्थितियों में उपयोगी है, लेकिन यह इस प्रश्न के साथ मदद नहीं करता है।
एलेजांद्रो

3

(एक व्युत्पन्न अभी तक पूर्ण व्युत्पत्ति देने के प्रयास में।)

हर इनपुट बाइट में 8 बिट्स होते हैं, इसलिए n इनपुट बाइट्स के लिए हमें मिलता है:

n × 8 इनपुट बिट्स

हर 6 बिट एक आउटपुट बाइट है, इसलिए:

Ceil ( n × 8/6 ) =  ceil ( n × 4/3 ) आउटपुट बाइट्स

यह बिना पैडिंग के है।

पैडिंग के साथ, हम कई-चार आउटपुट बाइट तक गोल करते हैं:

छत ( छत ( n × 4/3 ) / 4) × 4 =  छत ( n × 4/3/4 ) × 4 =  छत ( n / 3) × 4 आउटपुट बाइट्स

पहली समतुल्यता के लिए नेस्टेड डिवीज़न (विकिपीडिया) देखें ।

पूर्णांक अंकगणित का उपयोग करके, छत ( n / m ) की गणना ( n + m - 1) div m के रूप में की जा सकती है , इसलिए हम निम्न हैं:

( n * 4 + 2) div 3 बिना पैडिंग के

( n + 2) div 3 * 4 पैडिंग के साथ

चित्रण के लिए:

 n   with padding    (n + 2) div 3 * 4    without padding   (n * 4 + 2) div 3 
------------------------------------------------------------------------------
 0                           0                                      0
 1   AA==                    4            AA                        2
 2   AAA=                    4            AAA                       3
 3   AAAA                    4            AAAA                      4
 4   AAAAAA==                8            AAAAAA                    6
 5   AAAAAAA=                8            AAAAAAA                   7
 6   AAAAAAAA                8            AAAAAAAA                  8
 7   AAAAAAAAAA==           12            AAAAAAAAAA               10
 8   AAAAAAAAAAA=           12            AAAAAAAAAAA              11
 9   AAAAAAAAAAAA           12            AAAAAAAAAAAA             12
10   AAAAAAAAAAAAAA==       16            AAAAAAAAAAAAAA           14
11   AAAAAAAAAAAAAAA=       16            AAAAAAAAAAAAAAA          15
12   AAAAAAAAAAAAAAAA       16            AAAAAAAAAAAAAAAA         16

अंत में, MIME Base64 एन्कोडिंग के मामले में, प्रत्येक 76 आउटपुट बाइट्स के लिए दो अतिरिक्त बाइट्स (CR LF) की आवश्यकता होती है, एक टर्मिनेटिंग न्यूलाइन की आवश्यकता होती है या नहीं, इसके आधार पर गोल या ऊपर।


विस्तृत विश्लेषण के लिए धन्यवाद
पी सतीश पात्रो

2

मुझे लगता है कि सही सूत्र होना चाहिए:

n64 = 4 * (n / 3) + (n % 3 != 0 ? 4 : 0)

Ascii शून्य भरण को ध्यान में नहीं रखा जाता है - विंडोज में काम नहीं करता है। (क्रिप्टबाइनटाइनटॉस्ट्रिंगा)
टारमोपिकारो

1

मेरा मानना ​​है कि यह एक सटीक उत्तर है यदि n% 3 शून्य नहीं है, नहीं?

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

गणित संस्करण:

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

मज़े करो

सैनिक


1

जावास्क्रिप्ट में सरल कार्यान्वयन

function sizeOfBase64String(base64String) {
    if (!base64String) return 0;
    const padding = (base64String.match(/(=*)$/) || [])[1].length;
    return 4 * Math.ceil((base64String.length / 3)) - padding;
}

1

C बोलने वाले सभी लोगों के लिए, इन दो मैक्रोज़ पर एक नज़र डालें:

// calculate the size of 'output' buffer required for a 'input' buffer of length x during Base64 encoding operation
#define B64ENCODE_OUT_SAFESIZE(x) ((((x) + 3 - 1)/3) * 4 + 1) 

// calculate the size of 'output' buffer required for a 'input' buffer of length x during Base64 decoding operation
#define B64DECODE_OUT_SAFESIZE(x) (((x)*3)/4) 

यहां से ले गए ।


1

मैं अन्य प्रतिक्रियाओं में सरलीकृत सूत्र नहीं देखता हूं। तर्क कवर किया गया है, लेकिन मैं अपने एम्बेडेड उपयोग के लिए सबसे बुनियादी रूप चाहता था:

  Unpadded = ((4 * n) + 2) / 3

  Padded = 4 * ((n + 2) / 3)

नोट: अनप्लग किए गए गणना की गणना करते समय हम पूर्णांक डिवीजन को गोल करते हैं अर्थात इस मामले में Div2-1 जोड़ें जो +2 है


0

विंडोज़ में - मैं mime64 आकार के बफर के आकार का अनुमान लगाना चाहता था, लेकिन सभी सटीक गणना सूत्र ने मेरे लिए काम नहीं किया - आखिरकार मैंने इस तरह के अनुमानित सूत्र के साथ समाप्त कर दिया है:

Mine64 स्ट्रिंग आवंटन आकार (लगभग) = (((4 ((बाइनरी बफर आकार) + 1)) / 3) + 1)

तो अंतिम +1 - इसका उपयोग एएससीआई-शून्य के लिए किया जाता है - अंतिम पात्र को शून्य समाप्ति को संग्रहीत करने के लिए आवंटित करने की आवश्यकता है - लेकिन "बाइनरी बफर आकार" + 1 क्यों है - मुझे संदेह है कि कुछ mime64 समाप्ति वर्ण है? या हो सकता है यह कुछ संरेखण मुद्दा है।


0

यदि कोई JS में @Pedro सिल्वा समाधान को प्राप्त करने में रुचि रखता है, तो मैंने इसके लिए बस यही समाधान पोर्ट किया है:

const getBase64Size = (base64) => {
  let padding = base64.length
    ? getBase64Padding(base64)
    : 0
  return ((Math.ceil(base64.length / 4) * 3 ) - padding) / 1000
}

const getBase64Padding = (base64) => {
  return endsWith(base64, '==')
    ? 2
    : 1
}

const endsWith = (str, end) => {
  let charsFromEnd = end.length
  let extractedEnd = str.slice(-charsFromEnd)
  return extractedEnd === end
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.