জাভাস্ক্রিপ্টে স্ট্রিং দৈর্ঘ্য বাইটে


104

আমার জাভাস্ক্রিপ্ট কোডটিতে আমাকে এই ফর্ম্যাটে সার্ভারে একটি বার্তা রচনা করতে হবে:

<size in bytes>CRLF
<data>CRLF

উদাহরণ:

3
foo

ডেটাতে ইউনিকোডের অক্ষর থাকতে পারে। আমি তাদের ইউটিএফ -8 হিসাবে প্রেরণ করতে হবে।

আমি জাভাস্ক্রিপ্টে বাইটে স্ট্রিংয়ের দৈর্ঘ্য গণনা করার জন্য সর্বাধিক ক্রস ব্রাউজারের পথটি সন্ধান করছি।

আমি আমার পেডলোডটি রচনা করার জন্য এটি চেষ্টা করেছি:

return unescape(encodeURIComponent(str)).length + "\n" + str + "\n"

তবে এটি আমাকে পুরানো ব্রাউজারগুলির জন্য সঠিক ফলাফল দেয় না (বা ইউটিএফ -16 এর ব্রাউজারগুলির স্ট্রিংগুলি হতে পারে?)।

কোন সংকেত সনাক্ত করুন?

হালনাগাদ:

উদাহরণ: ЭЭХ! Naïve?ইউটিএফ -8 এ স্ট্রিংয়ের বাইটের দৈর্ঘ্য 15 বাইট, তবে কিছু ব্রাউজার তার পরিবর্তে 23 বাইট প্রতিবেদন করে।


1
সম্ভাব্য সদৃশ? stackoverflow.com/questions/2219526/…
এলি

@ এলি: আপনি যে প্রশ্নটির উত্তর দিয়েছেন তা আমার পক্ষে কাজ করার কোনও উত্তর নেই।
আলেকজান্ডার গ্ল্যাডিশ

আপনি যখন "ï! ভুতুড়ে" সম্পর্কে কথা বলবেন? আপনি কি এটি একটি নির্দিষ্ট সাধারণ ফর্ম মধ্যে স্থাপন করেছেন? unicode.org/report/tr15
মাইক স্যামুয়েল

@ মাইক: আমি এলোমেলো পাঠ্য সম্পাদকটিতে (ইউটিএফ -8 মোডে) টাইপ করেছি এবং এটি সংরক্ষণ করেছি। ঠিক যেমনটি আমার লাইব্রেরির কোনও ব্যবহারকারীই করতেন। যাইহোক, দেখে মনে হচ্ছে যে আমি কী ভুল বুঝতে পেরেছিলাম - আমার উত্তর দেখুন।
আলেকজান্ডার গ্ল্যাডিশ

উত্তর:


89

স্থানীয়ভাবে জাভাস্ক্রিপ্টে এটি করার কোনও উপায় নেই। ( আধুনিক পদ্ধতির জন্য রিকার্ডো গালির উত্তর দেখুন ))


Historicalতিহাসিক রেফারেন্সের জন্য বা যেখানে টেক্সট এনকোডার এপিআইগুলি এখনও অনুপলব্ধ

আপনি যদি চরিত্রের এনকোডিংটি জানেন তবে আপনি এটি নিজেই গণনা করতে পারেন।

encodeURIComponent UTF-8 কে অক্ষর এনকোডিং হিসাবে ধরে নিয়েছে, সুতরাং আপনার যদি সেই এনকোডিংয়ের প্রয়োজন হয় তবে আপনি এটি করতে পারেন,

function lengthInUtf8Bytes(str) {
  // Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence.
  var m = encodeURIComponent(str).match(/%[89ABab]/g);
  return str.length + (m ? m.length : 0);
}

ইউটিএফ -8 মাল্টি-বাইট সিকোয়েন্সগুলি এনকোড করার কারণে এটি কাজ করা উচিত। প্রথম এনকোডযুক্ত বাইটটি সর্বদা হয় একক বাইট অনুক্রমের জন্য উচ্চতর বিট দিয়ে শুরু হয়, বা এমন বাইট যার প্রথম হেক্স সংখ্যাটি সি, ডি, ই, বা এফ হয়। দ্বিতীয় এবং পরবর্তী বাইটগুলি হ'ল যার প্রথম দুটি বিট 10 আপনি যে অতিরিক্ত বাইটগুলি ইউটিএফ -8 এ গণনা করতে চান সেগুলি।

উইকিপিডিয়ায় সারণী এটি পরিষ্কার করে তোলে

Bits        Last code point Byte 1          Byte 2          Byte 3
  7         U+007F          0xxxxxxx
 11         U+07FF          110xxxxx        10xxxxxx
 16         U+FFFF          1110xxxx        10xxxxxx        10xxxxxx
...

পরিবর্তে যদি আপনার পৃষ্ঠা এনকোডিং বুঝতে হয় তবে আপনি এই কৌশলটি ব্যবহার করতে পারেন:

function lengthInPageEncoding(s) {
  var a = document.createElement('A');
  a.href = '#' + s;
  var sEncoded = a.href;
  sEncoded = sEncoded.substring(sEncoded.indexOf('#') + 1);
  var m = sEncoded.match(/%[0-9a-f]{2}/g);
  return sEncoded.length - (m ? m.length * 2 : 0);
}

আচ্ছা, আমি কীভাবে ডেটাটির অক্ষর এনকোডিং করব? আমার জেএস লাইব্রেরিতে যে কোনও স্ট্রিং ব্যবহারকারী (প্রোগ্রামার) সরবরাহ করেছেন তা আমাকে এনকোড করা দরকার।
আলেকজান্ডার গ্ল্যাডিশ

@ আলেকজান্দার, আপনি যখন সার্ভারে বার্তা প্রেরণ করছেন, আপনি কি এইচটিটিপি শিরোনামের মাধ্যমে বার্তাটির বডিটির সামগ্রী-এনকোডিং নির্দিষ্ট করছেন?
মাইক স্যামুয়েল

1
@ আলেকজান্ডার, দুর্দান্ত যদি আপনি কোনও প্রোটোকল স্থাপন করেন তবে ইউটিএফ -8 জারি করা পাঠ্য-বিনিময়টির জন্য দুর্দান্ত ধারণা। একটি কম ভেরিয়েবল যা মেলে না result ইউটিএফ -8 অক্ষর এনকোডিংয়ের নেটওয়ার্ক-বাইট-ক্রম হওয়া উচিত।
মাইক স্যামুয়েল 21

4
@ মাইকসামুয়েল: lengthInUtf8Bytesফাংশনটি এই বিপরীতে 2-বিএমপি অক্ষরের জন্য 5 প্রদান করে str.lengthI'll
লাউরি ওহের্ড

1
এই সমাধানটি দুর্দান্ত তবে utf8mb4 বিবেচনা করা হয় না। উদাহরণস্বরূপ, encodeURIComponent('🍀')হয় '%F0%9F%8D%80'
অ্যালবার্ট

117

বছর কেটে গেছে এবং আজকাল আপনি স্থানীয়ভাবে এটি করতে পারেন

(new TextEncoder().encode('foo')).length

মনে রাখবেন এটি এখনও আইই (বা এজ) দ্বারা সমর্থিত নয় (আপনি তার জন্য পলিফিল ব্যবহার করতে পারেন )।

এমডিএন ডকুমেন্টেশন

স্ট্যান্ডার্ড স্পেসিফিকেশন


4
কি দুর্দান্ত, আধুনিক পদ্ধতির। ধন্যবাদ!
কন আন্তোনাকোস

লক্ষ্য করুন যে এমডিএন ডকুমেন্টেশন অনুসারে , টেক্সট এনকোডারটি সাফারি (ওয়েবকিট) দ্বারা এখনও সমর্থিত নয়।
মাওর

TextEncodeসমর্থন শুধুমাত্র UTF-8 ক্রোম 53. যেহেতু
Jehong Ahn

1
আপনার যদি কেবল দৈর্ঘ্যের প্রয়োজন হয় তবে একটি নতুন স্ট্রিং বরাদ্দ করা, প্রকৃত রূপান্তরটি করা, দৈর্ঘ্য নেওয়া এবং তারপরে স্ট্রিংটি ফেলে দেওয়া ওভারকিল হতে পারে। একটি কার্যকারিতার জন্য উপরে আমার উত্তরটি দেখুন যা কেবল দক্ষতার সাথে দৈর্ঘ্যের গণনা করে।
lovasoa

66

এখানে একটি আরও দ্রুত সংস্করণ রয়েছে, যা নিয়মিত অভিব্যক্তি ব্যবহার করে না, বা এনকোডেরিউআইকিউম্পোনেন্ট () ব্যবহার করে না :

function byteLength(str) {
  // returns the byte length of an utf8 string
  var s = str.length;
  for (var i=str.length-1; i>=0; i--) {
    var code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s+=2;
    if (code >= 0xDC00 && code <= 0xDFFF) i--; //trail surrogate
  }
  return s;
}

এখানে একটি পারফরম্যান্স তুলনা করা হয়

এটি কেবল চারকোডএটি () উইকিপিডিয়া ইউটিএফ 8 , এবং ইউটিএফ 16 সার্গেট অক্ষরের বর্ণনার উপর ভিত্তি করে ফিরে আসা প্রতিটি ইউনিকোড কোডপয়েন্টের ইউটিএফ 8-এর দৈর্ঘ্য গণনা করে ।

এটি আরএফসি 3629 অনুসরণ করে (যেখানে ইউটিএফ -8 অক্ষর সর্বাধিক 4-বাইট দীর্ঘ)।


46

সাধারণ ইউটিএফ -8 এনকোডিংয়ের জন্য, তুলনায় কিছুটা ভাল সামঞ্জস্যের সাথে TextEncoder, ব্লব কৌশলটি করে। যদিও খুব পুরানো ব্রাউজারগুলিতে কাজ করবে না।

new Blob(["😀"]).size; // -> 4  

29

এই ফাংশনটি আপনার কাছে যে কোনও ইউটিএফ -8 স্ট্রিংয়ের বাইট আকার দেয়।

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

উৎস


এটি 'ユ ー ザ ー コ ー ー' স্ট্রিংয়ের সাথে কাজ করে না, 14 দৈর্ঘ্য প্রত্যাশিত কিন্তু 21
মে আবহাওয়া ভিএন

1
@ মেওয়েদারভিএন আপনার ভুল ユーザーコードদৈর্ঘ্যের বাইটগুলি সর্বদা 21 হয়, আমি এটি বিভিন্ন সরঞ্জামে পরীক্ষা করেছি; আপনার মন্তব্যে আরও সদয় হন;)
ক্যাপাইটেক্স

এই স্ট্রিংটি আমার মনে আছে পিএইচপি তে পরীক্ষা করা 14
মে ওয়েদার ভিএন

24

Buffer(কেবল নোডজেএসের জন্য) ব্যবহার করে অন্য একটি খুব সহজ পদ্ধতির :

Buffer.byteLength(string, 'utf8')

Buffer.from(string).length

1
আপনি একটি বাফার দিয়ে এড়িয়ে যেতে পারেন Buffer.byteLength(string, 'utf8')
জো

1
@ জো পরামর্শের জন্য ধন্যবাদ, আমি এটি অন্তর্ভুক্ত করার জন্য কেবল একটি সম্পাদনা করেছি।
ইভান পেরেজ

5

এর সমাধান খুঁজতে আমাকে কিছুক্ষণ সময় নিল রিএ্যাক্ট নেটিভের তাই আমি এটি এখানে রেখেছি:

প্রথমে bufferপ্যাকেজটি ইনস্টল করুন :

npm install --save buffer

তারপরে নোড পদ্ধতিটি ব্যবহার করুন:

const { Buffer } = require('buffer');
const length = Buffer.byteLength(string, 'utf-8');

4

আসলে, আমি বুঝতে পেরেছি কি সমস্যা আছে। কোডটি কাজ করার জন্য পৃষ্ঠাতে <head>এই ট্যাগটি থাকা উচিত:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

অথবা, মন্তব্যে প্রস্তাবিত হিসাবে, সার্ভার যদি HTTP প্রেরণ করে Content-Encoding শিরোনাম এটিও কাজ করা উচিত।

তারপরে বিভিন্ন ব্রাউজারের ফলাফলগুলি সামঞ্জস্যপূর্ণ।

এখানে একটি উদাহরণ:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  <title>mini string length test</title>
</head>
<body>

<script type="text/javascript">
document.write('<div style="font-size:100px">' 
    + (unescape(encodeURIComponent("ЭЭХ! Naïve?")).length) + '</div>'
  );
</script>
</body>
</html>

দ্রষ্টব্য: আমি সন্দেহ করি যে কোনও (যথাযথ) এনকোডিং নির্দিষ্ট করে দেওয়া এনকোডিংয়ের সমস্যার সমাধান করবে। এটি কেবল একটি কাকতালীয় বিষয় যে আমার ইউটিএফ -8 দরকার।


2
unescapeজাভাস্ক্রিপ্ট ফাংশন করা উচিত নয় ইউনিফর্ম রিসোর্স শনাক্তকারীগণ (কোনো URI) ডিকোড ব্যবহৃত হবে না।
লৌরি ওহের্ড

1
@ লৌরিহের্ড unescapeসত্যই কখনও ইউআরআই ডিকোড করতে ব্যবহার করা উচিত নয়। তবে, পাঠ্যটিকে ইউটিএফ -8 এ রূপান্তর করতে এটি সূক্ষ্মভাবে
টিএস

unescape(encodeURIComponent(...)).lengthসর্বদা সাথে বা বাইরে সঠিক দৈর্ঘ্য গণনা করে meta http-equiv ... utf8। কোনও এনকোডিংয়ের বিশদ ছাড়াই কিছু ব্রাউজারের সহজেই আলাদা পাঠ্য থাকতে পারে (প্রকৃত এইচটিএমএল পাঠ্যে নথির বাইটগুলি এনকোড করার পরে) যার দৈর্ঘ্য তারা গণনা করে। এটি কেবল দৈর্ঘ্যই নয়, পাঠ্যটিও মুদ্রণ করে সহজেই এটি পরীক্ষা করতে পারে।
টিএস

3

এখানে একটি স্ট্রিংয়ের ইউটিএফ -8 বাইট গণনা করার জন্য একটি স্বতন্ত্র এবং দক্ষ পদ্ধতি।

//count UTF-8 bytes of a string
function byteLengthOf(s){
	//assuming the String is UCS-2(aka UTF-16) encoded
	var n=0;
	for(var i=0,l=s.length; i<l; i++){
		var hi=s.charCodeAt(i);
		if(hi<0x0080){ //[0x0000, 0x007F]
			n+=1;
		}else if(hi<0x0800){ //[0x0080, 0x07FF]
			n+=2;
		}else if(hi<0xD800){ //[0x0800, 0xD7FF]
			n+=3;
		}else if(hi<0xDC00){ //[0xD800, 0xDBFF]
			var lo=s.charCodeAt(++i);
			if(i<l&&lo>=0xDC00&&lo<=0xDFFF){ //followed by [0xDC00, 0xDFFF]
				n+=4;
			}else{
				throw new Error("UCS-2 String malformed");
			}
		}else if(hi<0xE000){ //[0xDC00, 0xDFFF]
			throw new Error("UCS-2 String malformed");
		}else{ //[0xE000, 0xFFFF]
			n+=3;
		}
	}
	return n;
}

var s="\u0000\u007F\u07FF\uD7FF\uDBFF\uDFFF\uFFFF";
console.log("expect byteLengthOf(s) to be 14, actually it is %s.",byteLengthOf(s));

নোট করুন যে কোনও ইনপুট স্ট্রিংটি ইউসিএস -২ বিকৃত হলে পদ্ধতিটি ত্রুটি ফেলে দিতে পারে throw


3

নোডজেএস-এ, Buffer.byteLengthএই উদ্দেশ্যে বিশেষত একটি পদ্ধতি:

let strLengthInBytes = Buffer.byteLength(str); // str is UTF-8

নোট করুন যে ডিফল্টরূপে পদ্ধতিটি ধরে নিয়েছে যে স্ট্রিংটি ইউটিএফ -8 এনকোডিং-এ রয়েছে। যদি কোনও ভিন্ন এনকোডিং প্রয়োজন হয় তবে এটি দ্বিতীয় আর্গুমেন্ট হিসাবে পাস করুন।


strLengthInBytesকেবল স্ট্রিংয়ের মধ্যে অক্ষরের 'গণনা' জেনেও গণনা করা সম্ভব ? অর্থাত var text = "Hello World!; var text_length = text.length; // pass text_length as argument to some method?। এবং, কেবল রেফারেন্সের জন্য, পুনরায় Buffer- আমি কেবল এই উত্তরটি নিয়ে এসেছি যা আলোচনা করে new Blob(['test string']).sizeএবং নোডে Buffer.from('test string').length,। সম্ভবত এগুলি কিছু লোককেও সহায়তা করবে?
ব্যবহারকারী 1063287

1
@ user1063287 সমস্যাটি হ'ল অক্ষরের সংখ্যা সর্বদা বাইটের সংখ্যার সমতুল্য হয় না। উদাহরণস্বরূপ, সাধারণ ইউটিএফ -8 এনকোডিং হল একটি পরিবর্তনশীল প্রস্থের এনকোডিং, যার মধ্যে একটি একক অক্ষর 1 বাইট থেকে 4 বাইট আকারের হতে পারে। এজন্য এনকোডিং ব্যবহারের পাশাপাশি একটি বিশেষ পদ্ধতি প্রয়োজন।
বোয়াজ

উদাহরণস্বরূপ, একটি ইউটিএফ -8 স্ট্রিং 4 টি অক্ষর সহ কমপক্ষে 4 বাইট "দীর্ঘ" হতে পারে, যদি প্রতিটি অক্ষর মাত্র 1 বাইট হয়; এবং প্রতিটি অক্ষর 4 বাইট হলে সর্বাধিক 16 বাইট "দীর্ঘ"। উভয় ক্ষেত্রেই অক্ষরের সংখ্যা গণনা 4 এবং তাই বাইট দৈর্ঘ্যের জন্য একটি অবিশ্বাস্য পরিমাপ ।
বোয়াজ

1

এটি বিএমপি এবং এসআইপি / এসএমপি অক্ষরের জন্য কাজ করবে।

    String.prototype.lengthInUtf8 = function() {
        var asciiLength = this.match(/[\u0000-\u007f]/g) ? this.match(/[\u0000-\u007f]/g).length : 0;
        var multiByteLength = encodeURI(this.replace(/[\u0000-\u007f]/g)).match(/%/g) ? encodeURI(this.replace(/[\u0000-\u007f]/g, '')).match(/%/g).length : 0;
        return asciiLength + multiByteLength;
    }

    'test'.lengthInUtf8();
    // returns 4
    '\u{2f894}'.lengthInUtf8();
    // returns 4
    'سلام علیکم'.lengthInUtf8();
    // returns 19, each Arabic/Persian alphabet character takes 2 bytes. 
    '你好,JavaScript 世界'.lengthInUtf8();
    // returns 26, each Chinese character/punctuation takes 3 bytes. 

0

আপনি এটি চেষ্টা করতে পারেন:

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

এটা আমার জন্য কাজ করে.


ক্রোমে "â" এর জন্য 1 প্রদান করে
রিক করুন

প্রথম ইস্যুটি ff xff কে \ x7f এ পরিবর্তন করে স্থির করা যেতে পারে, তবে 0x800-0xFFFF এর মধ্যে কোডপয়েন্টগুলি 3 বাইট গ্রহণের সময় হিসাবে নেওয়া হবে বলে এই সত্যটি ঠিক করা যায় না
রিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.