ラベル 文字コード の投稿を表示しています。 すべての投稿を表示
ラベル 文字コード の投稿を表示しています。 すべての投稿を表示

2014年11月29日

encoding.js 1.0.12 リリースしました

JavaScript 文字コード変換ライブラリ encoding.js 1.0.12 リリース しました

アップデート内容

  • UTF-8 <=> JIS 変換テーブルのバグ修正 (文字化けが直りました)
  • JIS X 0208 を対象にした変換テストが通るようになりました
  • ファイルサイズが約60% 減りました
  • 実行速度が向上しました
  • convert で引数にオブジェクトが渡せるようになりました

UTF-8 <=> JIS 変換テーブルのバグ

UTF-8 から JIS, JIS から UTF-8 への変換テーブルが変なことになってました。
変換テーブルは MS 基本コードポイント (Unicode) を参照していましたが、 UTF-8 に変換する際に無効なコードポイントになってしまい文字化けが発生していました。
MS 基本コードポイントと IBM 基本コードポイントの差は以下のようになっています。

コードポイント:
文字名 IBM CP (Unicode) MS CP (Unicode) IBM CP (UTF-8) MS CP (UTF-8)
― (全角ダッシュ) U+2014 U+2015 E28094 E28095
~ (波形ダッシュ) U+301C U+FF5E E3809C EFBD9E
∥ (二重縦線) U+2016 U+2225 E28096 E288A5
- (負符号) U+2212 U+FF0D E28892 EFBC8D
U+00A2 U+FFE0 C2A2 EFBFA0
U+00A3 U+FFE1 C2A3 EFBFA1
U+00AC U+FFE2 C2AC EFBFA2

encoding.js の場合、MS コードポイントのまま変換しようとしていまい、対応する文字がなく '?' などになってしまっていました。
これは元々直したつもりでいたのですが、 encoding.js 1.0.10 Line 2973 あたりを見てみると以下のようになっていて
0xEFBC8F:0x213F,0xEFBCBC:0x2140,0xE3809C:0x2141,0xEFBD9E:0x2141,0xE288A5:0x2142,
そもそも 0x2141 が消しきれてなくて重複していたり、対応する JIS テーブルに文字がなくて変換すると 1文字分消えてしまったりと、 バグが多かったのですが
今回、IBM 基本コードポイントの差分によって変換してあげることで、ぶじ文字化けが解消されました。

JIS X 0208 を対象にした変換テストが通るようになりました

この変換テーブルの修正により、JIS X 0208-1997 (JIS規格 第一・第二水準漢字) を対象にした変換テスト (UTF-16, UTF-8, Shift_JIS, EUC-JP, ISO-2022-JP(JIS)) が通るようになりました。 また、Unicode サロゲートペア の処理も修正しています。

ファイルサイズが約60% 減りました

encoding.js では、変換テーブルだけでかなりのサイズを占めています。
前バージョンまでは、JIS→UTF-8 テーブルと UTF-8→JIS テーブルの 2つを保持していたのですが、
今回、UTF-8→JIS のみを静的に持ち、JIS→UTF-8 変換が必要になった際、動的にもう一つのテーブルを生成するようにしました。
生成されるのは呼ばれた最初の 1回のみです。
その際の速度が気になり、ベンチとってみましたが 約 2~5ms 程度で問題ないと思われます。
ファイルサイズは非minifyで 261KB (min: 219KB) だったのが 152KB (min: 116KB) になり、約60% 減らすことができました。

実行速度が向上しました

前までは、変換テーブルに文字があるかないかを、if (TABLE[c] === void 0) { ... } みたいな感じで判断していましたが、
これは非常に遅く、また in を使うより hasOwnProperty が速く、実行環境にもよりますが
var hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
if (hasOwn(obj, key)) { ... }
のように bind して使うよりも hasOwnProperty.call(obj, key) のほうが若干速かったため、後者を採用しています。

変換速度は、1MB の日本語テキスト (UTF-8) に対して SJIS に文字コード変換した場合、平均 約 50ms. (EUC-JP, JIS 等も同程度)、
UNICODE (UTF-16) から UTF-8 とその逆は約 5ms ほどで、前よりだいぶ速くなりました。

convert で引数にオブジェクトが渡せるようになりました

convert の第二引数に Object を渡せるようになりました。
// 以前の指定の仕方 (SJISに変換)
var sjisArray = Encoding.convert(unicodeArray, 'SJIS', 'UNICODE');

// Object で指定
var sjisArray = Encoding.convert(unicodeArray, {
  to: 'SJIS',
  from: 'UNICODE'
});
前のように 第二引数を to, 第三引数を from として文字列で渡しても動きます。


文字化けという大きなバグを修正しているので、アップデートをおすすめします。

Download


Node.js では、encoding-japanese というモジュール名になっています
npm install encoding-japanese
var encoding = require('encoding-japanese');

上のようにして利用できます。

encoding.convert() は Buffer に対しても使えます(配列で返ります)

Demo

Repository




2012年4月24日

JavaScriptで文字コード変換ライブラリ作ってみた

文字コード変換ライブラリを JavaScript で作りました。
文字列ではなく配列 or TypedArray で処理します。

追記

↓動作サンプルを作りました
文字コード変換 動作サンプル

Unicode の変換が可能になりました。
文字コード配列から URLエンコード/デコード が可能になりました。
あと説明とサンプルも少し載せました。。(説明不足でごめんなさい)

こないだの 「JavaScriptだけでzipファイルの解凍 - Unzipper.js」が
SJIS ファイルとかだと表示で文字化けするので、ついつい。。

動作確認は、zip ファイル解凍のデモページでわかると思います。
zip の中に SJIS や EUC-JP のファイル (ファイル名) がある場合でも
UTF-8 表示で化けなければ問題なしです。


↑のデモページを開いて、デスクトップなどから zip ファイルをドロップすると
解凍して結果のテキストを表示します。

※ JavaScript だけで動いていて、どっかのサーバなどに送信したり保存したりしてません


今回はぜんぶ同期で書いちゃったのですが、
バイナリファイルとかが対象だとちょっと重たくなりがち。。
気が向いたら非同期も可能にしてみたいです。

あと、Unzipper.js と同じレポジトリにしちゃったけど
これもできれば別にしたいところ。
追記→ 作りました

使い方:
// <script src="encoding.js"></script>
//
// Encoding というオブジェクトがグローバルに定義されます
// 配列に対して変換または判別します

// 文字コード変換
var utf8Array = new Uint8Array(...) or [...] or Array(...);
var sjisArray = Encoding.convert(utf8Array, 'SJIS', 'UTF8');

// 文字コード自動判別で変換
var sjisArray = Encoding.convert(utf8Array, 'SJIS');
// or  
var sjisArray = Encoding.convert(utf8Array, 'SJIS', 'AUTO');


// 文字コード判別 (戻り値は下の「共通の文字コード値」のいずれか)
var encoding = Encoding.detect(utf8Array);
if (encoding === 'UTF8') {
    alert('UTF8です');
}

// 特定の文字コードかどうか判別
var isSJIS = Encoding.detect(sjisArray, 'SJIS');
if (isSJIS) {
    alert('SJISです');
}

// convert, detect 共通の文字コード値:
//  - 'UTF32'   (detect only)
//  - 'UTF16'   (detect only)
//  - 'BINARY'  (detect only)
//  - 'ASCII'   (detect only)
//  - 'JIS'
//  - 'UTF8'
//  - 'EUCJP'
//  - 'SJIS'
//  - 'UNICODE' (JavaScript Unicode String/Array)
//
// ※ (detect only) は Encoding.detect() でのみ有効 (変換はできない)
// ※ 'UNICODE' は JavaScript の Unicode コード値 (0xFF 以上の数値になりえる)
//

サンプル:
// EUCJPの文字コード配列 (中身は 'こんにちは、ほげ☆ぴよ')
var eucjpArray = [
    164, 179, 164, 243, 164, 203, 164, 193, 164, 207, 161,
    162, 164, 219, 164, 178, 161, 249, 164, 212, 164, 232
];
// UTF-8に変換
var utf8Array = Encoding.convert(eucjpArray, 'UTF8', 'EUCJP');
console.log( utf8Array );
// output: [
//   227, 129, 147, 227, 130, 147, 227, 129, 171,
//   227, 129, 161, 227, 129, 175, 227, 128, 129,
//   227, 129, 187, 227, 129, 146, 226, 152, 134,
//   227, 129, 180, 227, 130, 136
// ]
//   => 'こんにちは、ほげ☆ぴよ'

// ---------------------------------------------
// 文字コード自動判別で変換
//

// SJISの文字コード配列 (中身は 'こんにちは、ほげ☆ぴよ')
var sjisArray = [
    130, 177, 130, 241, 130, 201, 130, 191, 130, 205, 129,
     65, 130, 217, 130, 176, 129, 153, 130, 210, 130, 230
];
// Unicodeに変換
var unicodeArray = Encoding.convert(sjisArray, 'UNICODE', 'AUTO');
// 文字列にして表示
// codeToStringは、文字コード配列を文字列に変換(連結)して返す関数
console.log( Encoding.codeToString(unicodeArray) );
//
// output: 'こんにちは、ほげ☆ぴよ'
//

// ---------------------------------------------
// 文字コードの配列をURLエンコード/デコード
var sjisArray = [
  130, 177, 130, 241, 130, 201, 130, 191, 130, 205, 129,
   65, 130, 217, 130, 176, 129, 153, 130, 210, 130, 230
];
var encoded = Encoding.urlEncode(sjisArray);
console.log(encoded);
// output:
//   '%82%B1%82%F1%82%C9%82%BF%82%CD%81A%82%D9%82%B0%81%99%82%D2%82%E6'

var decoded = Encoding.urlDecode(encoded);
console.log(decoded);
// output: [
//   130, 177, 130, 241, 130, 201, 130, 191, 130, 205, 129,
//    65, 130, 217, 130, 176, 129, 153, 130, 210, 130, 230
// ]

ダウンロード



レポジトリ



その他、なにか問題等あれば
コメントやメールまたは @polygon_planet まで送っていただけるとうれしいです。