जावास्क्रिप्ट स्ट्रिंग में कितने बाइट्स हैं?


97

मेरे पास एक जावास्क्रिप्ट स्ट्रिंग है जो UTF-8 में सर्वर से भेजे जाने पर लगभग 500K है। मैं जावास्क्रिप्ट में इसका आकार कैसे बता सकता हूं?

मुझे पता है कि जावास्क्रिप्ट UCS-2 का उपयोग करता है, इसलिए इसका मतलब है कि प्रति वर्ण 2 बाइट्स। हालाँकि, क्या यह जावास्क्रिप्ट कार्यान्वयन पर निर्भर करता है? या पेज एन्कोडिंग या शायद सामग्री-प्रकार पर?


लगभग। उत्तर लंबाई होगा * charsize, तो आपका अनुमान करीब है।
glasnt

1
आधुनिक जावास्क्रिप्ट, उदाहरण के लिए ईएस 6, केवल यूसीएस -2 का उपयोग नहीं करता है, यहां और अधिक विवरण: stackoverflow.com/a/46735247/700206
व्हाइटनीलैंड

जवाबों:


36

Stringमूल्य कार्यान्वयन पर निर्भर नहीं हैं, ECMA-262 3 डी संस्करण विशिष्टता के अनुसार , प्रत्येक वर्ण UTF-16 पाठ की 16-बिट इकाई का प्रतिनिधित्व करता है :

4.3.16 स्ट्रिंग मूल्य

एक स्ट्रिंग मान स्ट्रिंग का एक सदस्य है और शून्य या अधिक 16-बिट अहस्ताक्षरित पूर्णांक मानों का क्रमबद्ध क्रम है।

नोट यद्यपि प्रत्येक मान आमतौर पर UTF-16 पाठ की एक एकल 16-बिट इकाई का प्रतिनिधित्व करता है, भाषा उन मानों पर कोई प्रतिबंध या आवश्यकता नहीं रखती है सिवाय इसके कि वे 16-बिट अहस्ताक्षरित पूर्णांक हों।


8
उस मार्ग से मेरा पढ़ना स्वतंत्रता को लागू करने का नहीं है।
पॉल बिगगर

4
UTF-16 की गारंटी नहीं है, केवल स्ट्रिंग्स को 16-बिट इनट्स के रूप में संग्रहीत किया जाता है।
ब्योर्नल

यह केवल यूटीएफ -16 के संबंध में कार्यान्वयन-निर्भर है। 16-बिट चरित्र वर्णन सार्वभौमिक है।
पैंजरक्रिस 14

1
मुझे लगता है कि आंतरिक रूप से फ़ायरफ़ॉक्स भी कुछ तारों के लिए प्रति वर्ण 1 बाइट का उपयोग कर सकता है .... blog.mozilla.org/javascript/2014/07/21/…
Michal Charemza

1
UTF-16 को स्पष्ट रूप से जिस तरह से मैं इसे पढ़ रहा हूँ, अनुमति नहीं है। UTF-16 वर्णों में 4 बाइट्स हो सकते हैं, लेकिन युक्ति कहता है "मान 16-बिट अहस्ताक्षरित पूर्णांक होना चाहिए"। इसका मतलब यह है कि जावास्क्रिप्ट स्ट्रिंग मान यूटीएफ -16 का एक सबसेट हैं, हालांकि, 3 या 4 बाइट्स वर्णों का उपयोग करने वाले किसी भी यूटीएफ -16 स्ट्रिंग की अनुमति नहीं होगी।
व्हाइटनीलैंड

71

यह फ़ंक्शन आपके द्वारा पास किए गए किसी भी UTF-8 स्ट्रिंग के बाइट का आकार लौटाएगा।

function byteCount(s) {
    return encodeURI(s).split(/%..|./).length - 1;
}

स्रोत

जावास्क्रिप्ट इंजन आंतरिक रूप से UCS-2 या UTF-16 का उपयोग करने के लिए स्वतंत्र हैं। अधिकांश इंजन जिन्हें मैं यूटीएफ -16 के उपयोग के बारे में जानता हूं, लेकिन उन्होंने जो भी विकल्प बनाया, वह सिर्फ एक कार्यान्वयन विवरण है जो भाषा की विशेषताओं को प्रभावित नहीं करेगा।

हालांकि, ECMAScript / JavaScript भाषा UCS-2 के अनुसार वर्णों को उजागर करती है, UTF-16 के अनुसार नहीं।

स्रोत


9
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)इसके बजाय उपयोग करें । आपका स्निपेट उन स्ट्रिंग्स के लिए विफल रहता है जो "% uXXXX" को एन्कोड करते हैं।
रोब डब्ल्यू

वेबसोकेट फ़्रेम पर आकार गणना के लिए उपयोग किया जाता है, क्रोम देव उपकरण के रूप में स्ट्रिंग फ्रेम के लिए समान आकार देता है।
user85155

2
S3 पर अपलोड किए गए जावास्क्रिप्ट स्ट्रिंग्स के लिए प्रयुक्त, s3 बिल्कुल एक ही आकार (बाइटकाउंट (s)) / 1024) को प्रदर्शित करता है ।toFixed (2) + "KiB"]
user85155

49

यदि आप नोड। जेएस का उपयोग कर रहे हैं, तो बफ़र्स का उपयोग करके एक सरल समाधान है :

function getBinarySize(string) {
    return Buffer.byteLength(string, 'utf8');
}

इसके लिए एक npm लीब है: https://www.npmjs.org/package/utf8-binary-cutter (आपकी ओर से ईमानदारी से)


41

आप बाइट में स्ट्रिंग आकार प्राप्त करने के लिए ब्लॉब का उपयोग कर सकते हैं ।

उदाहरण:

console.info(
  new Blob(['😂']).size,                             // 4
  new Blob(['👍']).size,                             // 4
  new Blob(['😂👍']).size,                           // 8
  new Blob(['👍😂']).size,                           // 8
  new Blob(['I\'m a string']).size,                  // 12

  // from Premasagar correction of Lauri's answer for
  // strings containing lone characters in the surrogate pair range:
  // https://stackoverflow.com/a/39488643/6225838
  new Blob([String.fromCharCode(55555)]).size,       // 3
  new Blob([String.fromCharCode(55555, 57000)]).size // 4 (not 6)
);


2
भगवान का शुक्र है! यह संभवतः आधुनिक ब्राउज़रों के लिए स्वीकृत उत्तर होना चाहिए।
prasanthv

कैसे Node.js में बूँद आयात करने के लिए?
अलेक्जेंडर मिल्स

4
आह, Node.js के साथ हम बफ़र का उपयोग करते हैं, उदाहरण के लिएBuffer.from('😂').length
अलेक्जेंडर मिल्स

19

इस संयोजन का उपयोग unescape js फ़ंक्शन के साथ करें:

const byteAmount = unescape(encodeURIComponent(yourString)).length

पूर्ण सांकेतिक शब्दों में बदलना उदाहरण:

const s  = "1 a ф № @ ®"; //length is 11
const s2 = encodeURIComponent(s); //length is 41
const s3 = unescape(s2); //length is 15 [1-1,a-1,ф-2,№-3,@-1,®-2]
const s4 = escape(s3); //length is 39
const s5 = decodeURIComponent(s4); //length is 11

4
unescapeजावास्क्रिप्ट समारोह बहिष्कृत है और यूनिफ़ॉर्म रिसोर्स पहचानकर्ता (URI) को डिकोड करने के लिए नहीं किया जाना चाहिए। स्रोत
लॉरी ओहरड

@LauriOherd मुझे पता है कि टिप्पणी पुरानी है, लेकिन: इस उत्तर में, यूआरआई unescapeको डिकोड करने के लिए उपयोग नहीं किया जाता है। इसका उपयोग %xxदृश्यों को एकल वर्णों में बदलने के लिए किया जाता है । जैसा encodeURIComponentकि UTF-8 के रूप में एक स्ट्रिंग को एन्कोड करता है, कोडुनिट्स को या तो इसके संबंधित ASCII चरित्र के रूप में या एक %xxअनुक्रम के रूप में, मूल स्ट्रिंग के UTF-8 प्रतिनिधित्व वाले बाइनरी स्ट्रिंगunescape(encodeURIComponent(...)) में परिणाम कॉल करता है। सही ढंग से कॉल करने से यूटीएफ -8 के रूप में एन्कोडेड स्ट्रिंग के बाइट्स में आकार मिलता है। .length
टीएस

और हाँ ( un) escape1999 के बाद से पदावनत है लेकिन यह अभी भी हर ब्राउज़र में उपलब्ध है ... - कहा कि, इसे अलग करने का अच्छा कारण है। मूल रूप से कोई रास्ता नहीं है, उन्हें सही ढंग से उपयोग करने के लिए ( en- decodeURI( / Component) के साथ संयोजन में UTF8 को डीकोड करने के अलावा ) - या ( कम से कम) मैं ( un) के लिए कोई अन्य उपयोगी एप्लिकेशन नहीं जानता हूं escape। और आज UTF8 को एनकोड / डिकोड करने के लिए बेहतर विकल्प हैं (TextEncoder
TS

10

ध्यान दें कि यदि आप नोड को लक्षित कर रहे हैं। तो क्या आप उपयोग कर सकते हैं Buffer.from(string).length:

var str = "\u2620"; // => "☠"
str.length; // => 1 (character)
Buffer.from(str).length // => 3 (bytes)

7

यूटीएफ -8 प्रति कोड बिंदु पर 1 से 4 बाइट्स का उपयोग करके वर्णों को एन्कोड करता है। जैसा कि सीएमएस ने स्वीकार किए गए उत्तर में बताया, जावास्क्रिप्ट प्रत्येक चरित्र को आंतरिक रूप से 16 बिट्स (2 बाइट्स) का उपयोग करके संग्रहीत करेगा।

यदि आप स्ट्रिंग में प्रत्येक वर्ण को लूप के माध्यम से पार्स करते हैं और कोड बिंदु के अनुसार उपयोग किए जाने वाले बाइट्स की संख्या की गणना करते हैं, और फिर कुल संख्या को 2 से गुणा करते हैं, तो आपके पास उस यूटीएफ -8 एन्कोडेड स्ट्रिंग के लिए बाइट्स में जावास्क्रिप्ट का मेमोरी उपयोग होना चाहिए। शायद कुछ इस तरह:

      getStringMemorySize = function( _string ) {
        "use strict";

        var codePoint
            , accum = 0
        ;

        for( var stringIndex = 0, endOfString = _string.length; stringIndex < endOfString; stringIndex++ ) {
            codePoint = _string.charCodeAt( stringIndex );

            if( codePoint < 0x100 ) {
                accum += 1;
                continue;
            }

            if( codePoint < 0x10000 ) {
                accum += 2;
                continue;
            }

            if( codePoint < 0x1000000 ) {
                accum += 3;
            } else {
                accum += 4;
            }
        }

        return accum * 2;
    }

उदाहरण:

getStringMemorySize( 'I'    );     //  2
getStringMemorySize( '❤'    );     //  4
getStringMemorySize( '𠀰'   );     //  8
getStringMemorySize( 'I❤𠀰' );     // 14

6

ये 3 तरीके हैं जिनका मैं उपयोग करता हूं:

  1. TextEncoder ()

    (new TextEncoder().encode("myString")).length)

  2. बूँद

    new Blob(["myString"]).size)

  3. बफर

    Buffer.byteLength("myString", 'utf8'))


4

जावास्क्रिप्ट स्ट्रिंग का आकार है

  • पूर्व ES6 : 2 बाइट्स प्रति चरित्र
  • ES6 और बाद में: प्रति वर्ण 2 बाइट्स, या प्रति वर्ण 5 या अधिक बाइट्स

प्री-ईएस 6
हमेशा 2 बाइट्स प्रति चरित्र। UTF-16 की अनुमति नहीं है क्योंकि युक्ति कहता है "मान 16-बिट अहस्ताक्षरित पूर्णांक होना चाहिए"। चूंकि UTF-16 तार 3 या 4 बाइट वर्णों का उपयोग कर सकते हैं, यह 2 बाइट आवश्यकता का उल्लंघन करेगा। महत्वपूर्ण रूप से, जबकि UTF-16 पूरी तरह से समर्थित नहीं हो सकता है, मानक के लिए आवश्यक है कि उपयोग किए गए दो बाइट वर्ण मान्य UTF-16 वर्ण हों। दूसरे शब्दों में, पूर्व-ईएस 6 जावास्क्रिप्ट तार UTF-16 वर्णों के सबसेट का समर्थन करते हैं।

ES6 और बाद में
प्रति चरित्र 2 बाइट्स, या प्रति वर्ण 5 या अधिक बाइट्स। अतिरिक्त आकार खेलने में आते हैं क्योंकि ES6 (ECMAScript 6) यूनिकोड कोड पॉइंट से बचने के लिए समर्थन जोड़ता है । यूनिकोड से बचना इस तरह दिखता है: \ u {1D306}

प्रैक्टिकल नोट्स

  • यह किसी विशेष इंजन के आंतरिक कार्यान्वयन से संबंधित नहीं है। उदाहरण के लिए, कुछ इंजन पूर्ण यूटीएफ -16 समर्थन के साथ डेटा संरचनाओं और पुस्तकालयों का उपयोग करते हैं, लेकिन वे जो प्रदान करते हैं, वह पूर्ण यूटीएफ -16 समर्थन नहीं है। इसके अलावा एक इंजन बाहरी UTF-16 सहायता भी प्रदान कर सकता है लेकिन ऐसा करने के लिए अनिवार्य नहीं है।

  • ES6 के लिए, व्यावहारिक रूप से बोलने वाले वर्ण कभी भी 5 बाइट्स से अधिक नहीं होंगे (2 बिंदु बाइट के लिए एस्केप प्वाइंट + 3 बाइट्स के लिए यूनिकोड कोड बिंदु), क्योंकि यूनिकोड के नवीनतम संस्करण में केवल 136,755 संभावित वर्ण हैं, जो 3 बाइट्स में आसानी से फिट बैठता है। हालांकि यह तकनीकी रूप से मानक द्वारा सीमित नहीं है, इसलिए प्रिंसिपल में एक एकल चरित्र का उपयोग कर सकते हैं, कोड बिंदु के लिए 4 बाइट्स और कुल 6 बाइट्स।

  • बाइट के आकार की गणना के लिए यहां अधिकांश कोड उदाहरण ईएस 6 यूनिकोड कोड पॉइंट से बचने के लिए नहीं लगते हैं, इसलिए परिणाम कुछ मामलों में गलत हो सकते हैं।


1
बस सोच रहा था, यदि आकार प्रति वर्ण 2 बाइट्स है, तो 4 Buffer.from('test').lengthऔर Buffer.byteLength('test')(नोड में) बराबर क्यों है और 4 के new Blob(['test']).sizeबराबर भी है?
user1063287

प्री-ईएस 6: यूटीएफ -16 की अनुमति है: ईसीएमए -262 तीसरा संस्करण देखें (1999 से) : पेज एक कहता है कि यूसीएस 2 या यूटीएफ -16 की अनुमति है। पृष्ठ 5, स्ट्रिंग मान की परिभाषा: "... हालांकि प्रत्येक मान आमतौर पर UTF-16 पाठ की एक एकल-बिट इकाई का प्रतिनिधित्व करता है, ..."। पृष्ठ 81 पर एक तालिका है, जिसमें दिखाया गया है कि कैसे मेल खाने वाले सरोगेट जोड़े को चार UTF-8 बाइट्स के रूप में एन्कोड किया जाना है।
टीएस

"प्रति वर्ण" - यदि आपके द्वारा इसका मतलब है, प्रति "उपयोगकर्ता-कथित चरित्र" ( कल्पना , सरल व्याख्या ) यह 16bit कोड इकाइयों की किसी भी संख्या हो सकती है। यदि आप "कोडपॉइंट" के अनुसार हैं, तो यह UTF-16 में एक या दो 16bit कोड इकाइयाँ हो सकती हैं । (यह 2.5 कोड इकाइयाँ नहीं हो सकती हैं (या आपको 5 बाइट्स कैसे मिलते हैं?))
TS

एक जावास्क्रिप्ट स्ट्रिंग में प्रत्येक तत्व ( 16-बिट अहस्ताक्षरित पूर्णांक मान ("तत्व") वास्तव में आंतरिक रूप से दो बाइट्स द्वारा दर्शाया गया है, मानक में परिभाषित नहीं है। (और यह कैसे हो सकता है - जब तक कि जावास्क्रिप्ट प्रोग्राम को प्रदान किया गया इंटरफ़ेस मानक के अनुसार काम करता है सब कुछ उद्देश्य के रूप में काम करता है।) उदाहरण के लिए मोज़िला प्रति कोडन सिर्फ एक बाइट का
टीएस

यूनिकोड कोड पॉइंट एस्केप का स्ट्रिंग लेंथ से कोई लेना-देना नहीं है - यह सोर्स कोड में स्ट्रिंग्स को दर्शाने का एक नया तरीका है। ( '\u{1F600}'.length===2, ) '\u{1F600}'==='\uD83D\uDE00','\u{1F600}'==='😀'
TS

3

जावास्क्रिप्ट स्ट्रिंग में एक एकल तत्व को एक एकल UTF-16 कोड इकाई माना जाता है। यह कहना है, स्ट्रिंग्स वर्ण 16-बिट (1 कोड इकाई) में संग्रहीत हैं, और 16-बिट 2 बाइट्स (8-बिट = 1 बाइट) के बराबर है।

charCodeAt()विधि दिए गए इंडेक्स पर UTF-16 कोड इकाई का प्रतिनिधित्व 0 और 65535 के बीच एक पूर्णांक वापस जाने के लिए इस्तेमाल किया जा सकता।

codePointAt(), जैसे UTF-32 यूनिकोड वर्ण के लिए पूरे कोड बिंदु मान देने के लिए इस्तेमाल किया जा सकता।

जब एक 16-बिट कोड इकाई में UTF-16 वर्ण का प्रतिनिधित्व नहीं किया जा सकता है, तो इसमें एक सरोगेट जोड़ी होगी और इसलिए दो कोड इकाइयों (2 x 16-बिट = 4 बाइट्स) का उपयोग करें

विभिन्न एन्कोडिंग और उनके कोड पर्वतमाला के लिए यूनिकोड एनकोडिंग देखें ।


आप सरोगेट्स के बारे में जो कहते हैं, वह ईसीएमए स्क्रिप्ट युक्ति का उल्लंघन करता प्रतीत होगा। जैसा कि मैंने ऊपर टिप्पणी की, कल्पना के लिए प्रति चरित्र दो बाइट्स की आवश्यकता होती है, और सरोगेट जोड़े की अनुमति देने से यह उल्लंघन होगा।
व्हाइटनीलैंड

जावास्क्रिप्ट ईएस 5 इंजन USC-2 या UTF-16 का उपयोग करने के लिए आंतरिक रूप से स्वतंत्र हैं, लेकिन वास्तव में जो इसका उपयोग कर रहा है वह सरोगेट्स के साथ UCS-2 की तरह है। ऐसा इसलिए है क्योंकि यह सरोगेट हिस्सों को अलग-अलग वर्णों के रूप में उजागर करने की अनुमति देता है, एकल UTF-16 अहस्ताक्षरित पूर्णांक। यदि आप अपने स्रोत कोड में एक यूनिकोड वर्ण का उपयोग करते हैं जिसे एक 16-बिट कोड इकाई से अधिक का प्रतिनिधित्व करने की आवश्यकता है, तो एक सरोगेट जोड़ी का उपयोग किया जाएगा। यह व्यवहार चश्मा के उल्लंघन में नहीं है, अध्याय 6 स्रोत पाठ देखें: ecma-international.org/ecma-262/5.1
holmberd

2

लॉरी ओहरड का जवाब जंगली में देखे गए अधिकांश तारों के लिए अच्छी तरह से काम करता है, लेकिन अगर स्ट्रिंग में सरोगेट जोड़ी रेंज में 0 अक्षर, 0xD800 से 0xDFFF तक लोन वर्ण शामिल हैं, तो यह विफल हो जाएगा। उदाहरण के लिए

byteCount(String.fromCharCode(55555))
// URIError: URI malformed

यह लंबा कार्य सभी तारों को संभालना चाहिए:

function bytes (str) {
  var bytes=0, len=str.length, codePoint, next, i;

  for (i=0; i < len; i++) {
    codePoint = str.charCodeAt(i);

    // Lone surrogates cannot be passed to encodeURI
    if (codePoint >= 0xD800 && codePoint < 0xE000) {
      if (codePoint < 0xDC00 && i + 1 < len) {
        next = str.charCodeAt(i + 1);

        if (next >= 0xDC00 && next < 0xE000) {
          bytes += 4;
          i++;
          continue;
        }
      }
    }

    bytes += (codePoint < 0x80 ? 1 : (codePoint < 0x800 ? 2 : 3));
  }

  return bytes;
}

उदाहरण के लिए

bytes(String.fromCharCode(55555))
// 3

यह सरोगेट जोड़े वाले तारों के आकार की सही गणना करेगा:

bytes(String.fromCharCode(55555, 57000))
// 4 (not 6)

परिणामों की तुलना नोड के अंतर्निहित फ़ंक्शन के साथ की जा सकती है Buffer.byteLength:

Buffer.byteLength(String.fromCharCode(55555), 'utf8')
// 3

Buffer.byteLength(String.fromCharCode(55555, 57000), 'utf8')
// 4 (not 6)

1

मैं V8 इंजन के एक एम्बेडेड संस्करण के साथ काम कर रहा हूं। मैंने एक स्ट्रिंग का परीक्षण किया है। प्रत्येक चरण 1000 वर्णों को धक्का देना। UTF-8।

सिंगल बाइट (8bit, ANSI) चरित्र "ए" (हेक्स: 41) के साथ पहला परीक्षण। दूसरा परीक्षण दो बाइट चरित्र (16bit) "" (हेक्स: सीई ए 9) और तीसरा परीक्षण तीन बाइट चरित्र (24 बिट) "☺" (हेक्स: ई 2 98 बीए) के साथ।

सभी तीन मामलों में डिवाइस 888 000 अक्षरों और मेमोरी का उपयोग करके मेमोरी से बाहर प्रिंट करता है। 26 348 kb RAM में।

परिणाम: वर्ण गतिशील रूप से संग्रहीत नहीं होते हैं। और केवल 16 बिट के साथ नहीं। - ठीक है, शायद केवल मेरे मामले के लिए (एंबेडेड 128 एमबी रैम डिवाइस, वी 8 इंजन सी ++ / क्यूटी) - चरित्र एन्कोडिंग का जावास्क्रिप्ट इंजन के रैम में आकार के साथ कोई लेना-देना नहीं है। ईजी एन्कोडिंग, आदि केवल हाईलेवल डेटा ट्रांसमिशन और स्टोरेज के लिए उपयोगी है।

एंबेडेड या नहीं, तथ्य यह है कि वर्ण केवल 16 बिट में संग्रहीत नहीं हैं। दुर्भाग्य से मेरे पास कोई 100% उत्तर नहीं है, जावास्क्रिप्ट निम्न स्तर के क्षेत्र में क्या करता है। Btw। मैंने चरित्र "ए" की एक सरणी के साथ एक ही (पहले परीक्षण ऊपर) का परीक्षण किया है। हर कदम पर 1000 वस्तुओं को धक्का दिया। (बिल्कुल एक ही परीक्षण। बस प्रतिस्थापित स्ट्रिंग करने के लिए सरणी) और सिस्टम 1 337 000 की लंबाई और सरणी लंबाई 10 416 KB के बाद मेमोरी (वांटेड) से बाहर लाता है। इसलिए, जावास्क्रिप्ट इंजन सरल प्रतिबंधित नहीं है। यह एक अधिक जटिल है।


0

आप यह कोशिश कर सकते हैं:

  var b = str.match(/[^\x00-\xff]/g);
  return (str.length + (!b ? 0: b.length)); 

इसने मेरे लिए काम किया।


1
निश्चित रूप से यह मानता है कि सभी वर्ण अधिकतम 2 बाइट्स हैं? यदि 3 या 4 बाइट वर्ण हैं (जो UTF-8 में संभव हैं) तो यह फ़ंक्शन केवल उन्हें 2-बाइट वर्णों के रूप में गिना जाएगा?
एडम बर्ली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.