LoginSignup
5
4

More than 5 years have passed since last update.

Node.jsでnpmを使わずにShift_JISやeuc-jpを処理する

Last updated at Posted at 2019-03-21

Node core APIのi18nを活用しよう

用途

オフラインの時や共用サーバーで勝手にnpm install iconv-liteなどができない時、エクセルをワンライナーでサクッと処理したい時など

必要条件

  • v8.3.0以上
  • icudtXX[bl].datファイルが手元のマシンにある
    • XXはICUのバージョン、bかlかはendian
    • OSXなら/usr/share/icu/にプリインストールされてる(特定バージョンのみ)

確認方法

$node # REPLに入る
> process.version
'v8.3.0' # Node.jsのバージョンが満たしているか確認
> process.versions.icu
'59.1' # 必要なICUのバージョンを確認

上記の場合、icudt59b.datまたはicudt59l.datが必要

自分のMBPの場合、/usr/share/icu/icudt62l.datがあり、
手元のNode.jsのversionはv10.15.3なので利用可能(下表)

対応表(2019-03, v8.x/v10.x/v11.xのみ)1

Node.js ver ICU ver
v11.1.0 ~ 63
v11.0.0, v10.7.0 ~ 62
v10.0.0 ~ 61
v8.10.0 ~ 60
v8.3.0 ~ 59

ICU dataが手元にない場合

いずれもオフラインは厳しい

  • npm i full-icu / yarn add full-icu
    • Node.js verに対応するICU verをビルドしてくれる
    • node --icu-data-dir=./node_modules/full-icuで実行可
  • nodejs/nodeをfull ICUでbuild
    • ICUデータはオンラインからダウンロードしている
  • ICUのユーザーガイドを参考にbuildする
  • etc...

やり方

ex, euc-jp.txtというeuc-jpエンコードされたファイルを読み込みUTF8で出力

no_npm.js
const {TextDecoder} = require('util');
const {readFileSync} = require('fs');
const d = new TextDecoder('euc-jp');
const s = d.decode(readFileSync(0)); // fd=0: 標準入力
console.log(s);
$cat ./euc-jp.txt
�ۤ�
$cat ./euc-jp.txt | node --icu-data-dir=/usr/share/icu/ no_npm.js
ほげ

解説

  • encodingオプションを指定せず生のbufferで読み込む
    • ここで'euc-jp'と指定できれば楽なのだが、TextDecoderでしかi18n対応がされておらず、encodingに指定できる値はENUM値で決まってしまっている
    • ex, readFileでは第二引数のオプションで指定しなければencodeのデフォルトはnull
    • cf, Buffer.from()の第二引数のencodeのデフォルトは'utf-8'
  • TextDecoderでencodingオプションを指定する
  • --icu-data-dirでicudtXX[bl].datがあるディレクトリを指定して実行する
    • これが指定できないとTextDecoderはデフォルトではutf-8utf-16leしかサポートしていないのでできない

できないこと

上記でUTF-8への変換はできたが、それをeuc-jpでencodeすることはできない。
同様にjsのstring(utf-16エンコードされるらしい)をeuc-jpで吐き出すことも自前で変換表を作らないと難しい。

Transcode(require('buffer').transcode())でできないかと期待したけど、指定可能なencodeは決まっていた。
https://github.com/nodejs/node/blob/master/src/node_i18n.cc

Appendix

Node verとICU verの対応の調べ方

$git clone git@github.com:nodejs/node.git
$cd node
$git log -p deps/icu-small/README-SMALL-ICU.txt
# 変更差分からICU verが更新(ex, commit messageに`bump`を含む、など)されたcommit番号をコピーし、下記でその番号を含むtagを検索
$git tag -l --contain 538acead6670d711ddb71c0b852089b792c996e3
v11.0.0
v11.1.0
v11.10.0
v11.10.1
v11.11.0
v11.12.0
v11.2.0
v11.3.0
v11.4.0
v11.5.0
v11.6.0
v11.7.0
v11.8.0
v11.9.0
# ただしこれだけだとmasterブランチ経由で変更されたものしか取得できない
# 例えばv8系の変遷を正しく知るには、v8系の最新のtagで調査する必要がある
$git checkout -b v8.15.1 refs/tags/v8.15.1

  1. 最新情報はAppendixを参考に調査ください 

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4