Help us understand the problem. What is going on with this article?

JavaScript、Node.js で文字列とバイト列の相互変換

More than 1 year has passed since last update.

概要

Encoding API を使って文字列とバイト列の相互変換に取り組みました。バイト列は Uint8Array であらわされ、Fetch API は Uint8Array の送受信をサポートします。
Node.js の場合、Buffer を使います。Encoding API を使いたい場合、ポリフィルを導入する必要があります。

文字列と Uint8Array の相互変換

TextEncoder は文字列を Uint8Array に変換します。デフォルトのエンコーディングは utf-8 です。

> (new TextEncoder).encode('')
Uint8Array(3) [227, 129, 130]
> (new TextEncoder('utf-8')).encode('')
Uint8Array(3) [227, 129, 130]
> (new TextEncoder).encoding
"utf-8"

16進数文字列を求めるには配列に変換します。

> Array.from((new TextEncoder('utf-8')).encode('')).map(v => v.toString(16))
> (3) ["e3", "81", "82"]

TextDecoder は Uint8Array を文字列に変換します。

> (new TextDecoder).decode(Uint8Array.of(0xe3, 0x81, 0x82))
""
> (new TextDecoder).decode(Uint8Array.from([0xe3, 0x81, 0x82]))
> ""
> (new TextDecoder).decode(new Uint8Array([0xe3, 0x81, 0x82]))
""

デフォルトのエンコーディングは utf-8 です。

> (new TextDecoder('utf-8')).decode(Uint8Array.of(0xe3, 0x81, 0x82))
""

スプレッド演算子を使って Uint8Array.of に配列を渡すこともできます。

> (new TextDecoder).decode(Uint8Array.of(...[0xe3, 0x81, 0x82]))
""

Uint8Array と16進数文字列の相互変換

Uint8Array を配列に変換して要素を連結させます。

> Uint8Array.of(0xe3, 0x81, 0x82)
Uint8Array(3) [227, 129, 130]
> Array.from(Uint8Array.of(0xe3, 0x81, 0x82)).map(v => v.toString(16)).join('')
"e38182"

今度は16進数文字列を Uint8Array に変換させてみましょう。

> str = 'e38182'
"e38182"
> arr = new Uint8Array(str.match(/.{1,2}/g).map(v => parseInt(v, 16)))
Uint8Array(3) [227, 129, 130]

Array.from を使うやり方もあります。

> str = 'e388182'
"e388182"
> Array.from({length: Math.ceil(str.length/2)}, (v, i) => str.substr(i * 2, 2))
(3) ["e3", "88", "18"]

ジェネレーターを使うやり方は次のとおりです。

> str = 'e38182'
'e38182'
> Array.from((function*(index, max, step) {
  while (index < max) {
    yield str.substr(index, step);
    index += step;
  }
})(0, str.length, 2));
[ 'e3', '81', '82' ]

バイトサイズ

Uint8Array.prototype.byteLength でバイトサイズを求めることができます。

> (new TextEncoder).encode('').byteLength
3

for-of ループで1バイトずつ数えてバイトサイズを求めることもできます。

> size = 0; for(v of (new TextEncoder).encode('')) { size++; }; size
3

Node.js

text-encoding の導入

Node.js で Encoding API を使いたい場合、text-encoding パッケージを導入します。

yarn add text-encoding

CommonJS 形式でクラスを読み込むには次のように書きます。

const textEncoding = require('text-encoding');
const TextEncoder = textEncoding.TextEncoder;
const TextDecoder = textEncoding.TextDecoder;

ES2015 モジュール形式で読み込むには Node.js 実行時に --experimental-modules を指定します。2017年9月時点では次のように書く必要がありました。

import * as textEncoding from 'text-encoding';
const TextEncoder = textEncoding.default.TextEncoder;
const TextDecoder = textEncoding.default.TextDecoder;

文字列と Buffer、Uint8Array の相互変換

文字列を Buffer に変換するには from メソッドを使います。デフォルトのエンコーディングは utf-8 です。

> Buffer.from('')
<Buffer e3 81 82>
> Buffer.from('', 'utf-8')
<Buffer e3 81 82>

Buffer から文字列に変換するには toString を使います。

> Buffer.from('').toString()
''
> Buffer.from('').toString('utf-8')
''

ES2015 で導入された Uint8ArrayBuffer を読み込むことができます。

> Uint8Array.from(Buffer.from(''))
Uint8Array [ 227, 129, 130 ]

逆に BufferUint8Array を読み込むことができます。

> Buffer.from(Uint8Array.from(Buffer.from(''))).toString()
''

Buffer と16進数文字列の相互変換

エンコーディングに 'hex' を指定します。

> Buffer.from('').toString('hex')
'e38182'
> Buffer.from([0xe3, 0x81, 0x82]).toString('hex')
'e38182'
> Buffer.from('e38182', 'hex')
<Buffer e3 81 82>

Buffer、Uint8Array と配列の相互変換

Buffer、Uint8Array から配列の変換には Array.from を使うことができます。

> Buffer.from([0xe3, 0x81, 0x82])
<Buffer e3 81 82>
> Uint8Array.from([0xe3, 0x81, 0x82])
Uint8Array [ 227, 129, 130 ]
> Array.from(Buffer.from([0xe3, 0x81, 0x82]))
[ 227, 129, 130 ]
> Array.from(Uint8Array.from([0xe3, 0x81, 0x82]))
[ 227, 129, 130 ]

Array.from はイテレーター (valuesentries)に対しても使うことができます。

> Array.from(Buffer.from([0xe3, 0x81, 0x82]).values())
[ 227, 129, 130 ]
> Array.from(Uint8Array.from([0xe3, 0x81, 0x82]).values())
[ 227, 129, 130 ]
> Array.from(Buffer.from([0xe3, 0x81, 0x82]).entries())
[ [ 0, 227 ], [ 1, 129 ], [ 2, 130 ] ]
> Array.from(Uint8Array.from([0xe3, 0x81, 0x82]).entries())
[ [ 0, 227 ], [ 1, 129 ], [ 2, 130 ] ]

... 演算子を使うこともできます。

> [...Buffer.from([0xe3, 0x81, 0x82]).values()]
[ 227, 129, 130 ]
> [...Buffer.from([0xe3, 0x81, 0x82]).entries()]
[ [ 0, 227 ], [ 1, 129 ], [ 2, 130 ] ]

バイトサイズ

> Buffer.byteLength('あいうえお')
15
> Buffer.byteLength('あいうえお', 'utf-8')
15
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした