銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

JavaScriptで文字列のバイト数を得るにはどーする?

f:id:takamints:20191123221032j:plain
photo credit: wuestenigel White tape measure via photopin (license)

ブラウザのJavaScriptとNode.jsで文字列のバイト長を知る方法です。文字数ではありません。 それぞれの環境でやり方が違いますが、統一コードも紹介してます。



目次

はじめに

JavaScriptで文字列のバイトサイズを取得する方法」を検索すると「URLエンコードして文字数を数える」って方法が検索結果の上位にたくさん出てきます。 しかし「こうすればできる」って感じがちょっとアヤシイ。

たいていはNode.jsに言及していないため、

「割と古い方法なのかな?最新式のJavaScriptではもっとスッキリした方法があるのでは?」

と思いまして「ブラウザのJavaScriptとNode.jsの両方の環境で、文字列のバイト長を求める方法」を調べてみました。

結果として、納得できるスッキリした方法がありましたけど、両環境では別方法。 まあ、どちらでも同じやり方が可能なモジュールもありましたので、それも含めて以降で説明しています。

ブラウザでは Blob を使う

ブラウザのJavaScriptでは (new Blob(["文字列"])).size で文字列のバイトサイズが得られます。

少し直感的でないので、関数として書けば以下のようになりますね。

/**
 * 文字列のバイト長を得る(ブラウザ版)。
 * 文字数ではありません。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return (new Blob([s])).size;
}

Blobはブラウザでバイナリデータを扱うためのクラスです詳細は以下。 上で使っているのはコンストラクタとsizeプロパティだけですね。

developer.mozilla.org

Node.js では Buffer クラスを使います。

Node.jsなら、Buffer.byteLength("文字列") でOKらしい。こちらはかなり直感的です。

/**
 * 文字列のバイト長を得る(Node.js版)。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return Buffer.byteLength(s);
}

nodejs.org

実行時に切り替えるには?

実行時に動作環境がブラウザであるのかNode.jsであるのかを調べて切り替えるには、以下のようにすればよろしいです。

/**
 * 文字列のバイト長を得る。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
const byteLengthOf =
    ("window" in (Function("return this;")()) ?
        s => (new Blob([s])).size : // ブラウザ版
        s => Buffer.byteLength(s)); // Node.js版

npm buffer で統一できる

と、ここまで書いて気になって、追加で調べてみたのですが、 Node.jsのBufferクラスをブラウザのJavaScriptで使えるようにした buffer というnpmモジュールがありました。 最初に調べるべきだったかもしれない。

www.npmjs.com

Bundlerが使える場合

WebPackやParcelなどのBundlerを使っているなら、以下のようにrequireで読み込めば(パスにちょっと注意)、 ブラウザのJavaScriptでも Node.js版のコードが使えます。そしてNode.jsでも動作しました。

const Buffer = require('buffer/').Buffer  // 注意:最後のスラッシュは重要!
/**
 * 文字列のバイト長を得る。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return Buffer.byteLength(s);
}

Bundlerが使えない場合

Bundlerを使えない場合は、ビルド済みスクリプト( https://bundle.run/buffer )をHTMLのSCRIPTタグで読み込めば Buffer クラスが使えるようになるらしい(こちらに関しては未検証です)。

<script src="https://bundle.run/buffer"></script>
/**
 * 文字列のバイト長を得る。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return Buffer.byteLength(s);
}

あとがき

検索でトップに出てくる情報が完全に正しい情報だとは限らないと思いました。 この場合は、完全な間違いとも言い切れませんが。

JavaScriptは既にかなりな歴史が積み重なっていて、徐々に仕様が整備されてきたので、どうしても古い情報が残りがちですね。 これから始めようとする人たちにとっては弊害となることがありそうな気もします。

このような点からも、最近はPythonが流行っているということもあるのかなと(知らんけど)

このような心配とはまた別に、JavaScriptではnpmとかBundlerの類はストレスなく使えるようになっておいたほうが良さそうですね。 モダンJavaScriptバンザイです。いくつになってもお勉強です。