あれから6年?(大笑
結局何が原因でうまくいかなかったのかと云えば
FileReader.readAsText(${Blob型データ},”SJIS”);に
未定義あるいはUTF16に変換できない文字を与えるとの大雑把には
- シフトJISの下位コードのMSBが0の場合は、「0xfffd」「下位コード」の2バイトに変換。
- シフトJISの下位コードのMSBが1の場合は、「0xfffd」の1バイトに変換。
している様に見えるが・・・
Blobに1文字づつ入れFileReaderで読むと
- シフトJISの下位コードのMSBに関わらず、「0xfffd」の1バイトに変換。
してしまうので
Blobに複数の文字を入れると、
挙動が不安定になるらしい。
なので、
1文字づつシフトJISをUTF16に変換してシフトJIS変換表を作成するしかない様だ。
実際に動かしてみると、
1秒もかからず変換表を作ってしまうので
これでいいんじゃないかな?
まだ、黑(fc4f)付近で変換に失敗している???
あ、文字領域が拡張されていたw(6年の重みかな?
f040~fc7e、f080~fcfcを変換表に追加。
ついでに外部変数を止めPromiseでガガガと作らせようとしたら・・・
Promiseを100個以上作るとPromise.Allでうまく処理できない ※返事が返ってこない。
ので、awaitで順次処理に変えてみる。※asyncも付けまくる。
さらにダウンロードの直前に変換表を作り直してみると
3秒くらいかかってしまった。
変換表をjsファイルでダウンロードできるようにした方がいいかな?
サンプルをSJIS変換を使って作成してみた。
やはり処理時間が長めだな。
あれ?未定義な文字しかない行が結構ある!
カット!
ちゃんと処理時間を表示してみると長めだなぁ。
サンプルをiframe化しUTF16未対応文字は□に変えてみた。
さらに、EUCとかも対応できそうなのでやってみた。
※サンプル
まだ、EUC-jpやiso-2022-jpでコードページを変更するコード(エスケープシーケンス等)が必要な文字は変換時に化けてしまう。
どんどん遅くなっていく。(キニシナイ
外部変数アクセスするのを減らそうとawaitしてみるとasync宣言付けたアロー関数だらけ。
Promise と resolve と await を良い塩梅で混ぜないといけないのも大変。
一番困ったのはVisualStudio Codeでデバッグしてみると
頻繁にPromise.allが暴走するが
それは非同期処理中はエラっても「デバッグコンソール」は裏に隠れたままなので、
SyntaxErrorがあっても気が付かないせい。
暫くしても処理が終わらないなぁ?と思い、
「問題」「出力」「デバッグコンソール」「ターミナル」タグをひっくり返してみると。
xxx変数は未定義です。
とか
xxxにmapプロパティは存在しません。
が見つかる。
でもデバッグを再開してもコンソールは初期化されないので、 2024/3/21現在はクリアされてる。
エラったらコンソールをクリアしてからデバッグしなおさないと泥沼。
postMessageでiframeとやり取りしているので、サンプルに入力した内容等がブラウザの他のタブにもpostされている可能性があります。
またサロゲートペア(𩸽:U+D867とU+DE3D、𠮷:U+D842とU+DFB7とか)にも対応していません。
※サロゲートペアは入力したいサロゲートペア文字の16進コードが判れば、IMEパッドの文字カデゴリの上位サロゲートD867の枠をクリックすると�っぽく表示されますが下位サロゲートからDE3Dの枠をクリックすると𩸽に変わります。
と云うのも、サロゲートペアはUTF16独自のものでSJIS文字に対応する文字の定義が無いっぽいです。SJIS変換表はSJISの文字領域に対して作成していますが行頭の””で囲まれた文字に上記のサロゲートペアが無いのです。または「部」から11画の魚辺の終わりの方にある𩸽を探し出すかですね。
JIS第4水準の第93区に𩸽が、AJ1ベース文字-JIS外に𠮷があるっぽいですが、ISO-2022-JPのザックリとしたエスケープシーケンスでは得られないっぽいです。
- ASCII: 1b 28 42
- JIS X 0208: 1b 24 42
一応、ISO-2022-JP-2004も追加してみたけどブラウザ未対応のencoding名らしく組み込んだエスケープ文字がそのまま出力され全角どころか半角すらちゃんと出なくなってしまう。
encodingx.jsのconst encodingInfoList をイジるとブラウザが対応している色々なencodingを試せます。
JISの様に文字の前にエスケープシーケンスが必要なものは配列の5~6番目に配列で記入できます。
- 5番目は文字を全角等に切替るシーケンス
- 6番目は半角に戻すシーケンス。
ここに新たなencodingを追加すればHTMLのselectの項目も自動的に増えます。
※まともに動作するかどうかは不明だけど
/**
* エンコーディング情報
* {
* "encoding": {
* 8: [
* [上位開始バイト,上位終了バイト,下位開始バイト,下位終了バイト,[接頭語...],[接尾語...]]
* ...
* ],
* 16: [
* [上位開始バイト,上位終了バイト,下位開始バイト,下位終了バイト,[接頭語...],[接尾語...]]
* ...
* ],
* },
* ...
* }
*/
const encodingInfoList = {
"windows-1252": {
// 8ビット
8: [
[0x0000, 0x0000, 0x0000, 0x00ff],
],
},
"shift-jis": {
// 8ビット
8: [
[0x0000, 0x0000, 0x0000, 0x00ff],
],
// 16ビット
16: [
// 第1面
[0x0081, 0x009f, 0x0040, 0x007e],
[0x0081, 0x009f, 0x0080, 0x00fc],
[0x00e0, 0x00ef, 0x0040, 0x007e],
[0x00e0, 0x00ef, 0x0080, 0x00fc],
// 第2面
[0x00f0, 0x00fc, 0x0040, 0x007e],
[0x00f0, 0x00fc, 0x0080, 0x00fc],
],
},
"iso-2022-jp": {
8: [
// 8ビット
[0x0000, 0x0000, 0x0000, 0x00ff, [0x1B, 0x28, 0x42], []],
],
16: [
// JIS X 0208コード表 1面
//
// 記号、英数字、かな(01区~08区)
[0x0021, 0x0028, 0x0020, 0x007f, [0x1B, 0x24, 0x42], [0x1B, 0x28, 0x42]],
// 第1水準漢字(16区~47区)
[0x0030, 0x004f, 0x0020, 0x007f, [0x1B, 0x24, 0x42], [0x1B, 0x28, 0x42]],
// 第2水準漢字(48区~84区)
[0x0050, 0x0073, 0x0020, 0x007f, [0x1B, 0x24, 0x42], [0x1B, 0x28, 0x42]],
[0x0074, 0x0074, 0x0020, 0x002f, [0x1B, 0x24, 0x42], [0x1B, 0x28, 0x42]],
],
},
"iso-2022-jp-2004": {
8: [
// ASCII
[0x0000, 0x0000, 0x0000, 0x00ff, [0x1B, 0x28, 0x42], []],
],
16: [
// JIS X 0213漢字集合1面:コード表
// 1面(JIS X 0208および第3水準漢字)(01区~94区)
[0x0021, 0x007e, 0x0020, 0x007f, [0x1B, 0x24, 0x28, 0x51], [0x1B, 0x28, 0x42]],
// JIS X 0213漢字集合2面:コード表
// 2面(第4水準漢字)(01区~08区)
[0x0021, 0x007e, 0x0020, 0x007f, [0x1B, 0x24, 0x28, 0x50], [0x1B, 0x28, 0x42]],
],
},
"euc-jp": {
// 8ビット
8: [
[0x0000, 0x0000, 0x0000, 0x007f],
[0x0000, 0x0000, 0x00a0, 0x00df, [0x8e], []],
],
// JIS X 0208コード表 1面
//
// 記号、英数字、かな(01区~08区)
16: [
[1 + 0x0a0, 8 + 0x0a0, 0 + 0x0a0, 95 + 0x0a0],
// 第1水準漢字(16区~47区)
[16 + 0x0a0, 47 + 0x0a0, 0 + 0x0a0, 95 + 0x0a0],
// 第2水準漢字(48区~84区)
[48 + 0x0a0, 83 + 0x0a0, 0 + 0x0a0, 95 + 0x0a0],
[84 + 0x0a0, 84 + 0x0a0, 0 + 0x0a0, 15 + 0x0a0],
],
},
};
ここまでくるとブラウザのJavaScriptのreadAsTextのencodingのチェッカーっぽくなってきた。(笑
今更UTF-8以外のテキストデータをブラウザで使う意味は遠の昔に消えているので、
ExcelがUTF-8のCSVをちゃんと読める様になったら、もう存在意義が無いに等しい。(大笑
なので、あて名書き5をアップ。おっと2014年?2024年に修正っと(笑
なんてこった10年も経ってたのか!
ps.2024/2/13
readAsTextで1文字づつ処理するのはやはり遅い。文字間にNULエリアを挿入してみたら文字同士の影響が無い様なので、エスケープシーケンスも考慮して16バイト毎に文字を配置することで、データの下位バイトの範囲単位で(サンプルの場合は1行単位)で処理するように修正したら、1秒以内に処理を終える様にしたのでchromeで見ているなら【24時間以内の履歴を削除】するとサンプルの変換処理が妙に速くなる。(ハズ
全データの範囲を一度に処理すればもっと速くなるハズ。
ps.2025/4/10
@returnを追記すらのでハイライトの行番号も修正
ps.2025/4/19
encodingInfoListにbig5を追加してみた。運悪く2バイト目が0x7EでmakeSampleRowで不具合が起きたので修正。ファビコンを表示。<DOCTYPE html>になってるトコ多いな~アップロードした状況でbig5で【ダウンロード】押すとalert表示する 8: […] が無いせいなので修正。
ps.2025/4/25
【変換表をダウンロード】するとエラっていたので修正。
big5で下位バイトが「0x00a1」と1から始まるとダンプも1から始まってたので0から始まる様に修正
いつのまにか変換範囲が増加してる時に対応してる状況に対応するために
コードページ選択時にサンプルと一緒にソースのエンコード情報も表示させるようにした。
ココで必要な部分だけ残して【エンコード情報からサンプル表示】ボタンを押すと
エンコーディング情報で指定した範囲でサンプルを表示する。
いつのまにか「ブラウザが変換しない文字」を 表示になっていたので■を表示するようにした。
ps.2025/4/25その2
iframeの中は簡単には操作できないが
const iframe = document.querySelector('iframe');
const doc = iframe.contentWindow.document; // 👈この辺はコロコロ変わってる様なのでデバッガで要確認
doc.open();
doc.write(`AAAAABBBBBCCCC`);
doc.close();
は表示できるけど、metaタグこみで
const iframe = document.querySelector('iframe');
const doc = iframe.contentWindow.document; // 👈この辺はコロコロ変わってる様なのでデバッガで要確認
doc.open();
doc.write(`<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=sjis">
<meta http-equiv="Cache-Control" content="no-cache">
<title>UTF16をSJISとかに変換するサンプル5</title>
<link href="encodingtest.css" media="all" rel="stylesheet" type="text/css" />
<script src="encodinglib.js"></script>
<script src="message.js"></script>
<script src="encodingx.js"></script>
<script src="download.js"></script>
<script src="encodingsample.js"></script>
</head>
<body>
<div class="sample" contenteditable id="sampleText"></div>
</body>
</html>`);
doc.close();
はダメっぽく、偶然に動いた(?)時もcharsetはUTF-8のままだった。
iframeが非推奨ポクなってきたのでIFRAME廃止版。一応旧版は残しておく。
当初の目標が遠くなったせいでガッカリしてたのか奇妙なバグが残る。
【ダウンロード】ボタンを押した後に【~サンプル表示】ボタンを押すとサンプルが■だらけになった。8ビットのコードは影響が無く、下位バイト分の変換表を作るトコロで上書きを繰り返していて「最後の下位バイト分ダケの変換表」の変換表になっていた。
入口が2通りあると陥るバグ。(あるある
ついでに doc.close(); の消し残しもあった。
うん。今日は散々だな。