JS: Netscape 4 では機種依存文字が "?" に置換される

日本語 Windows 上で、Netscape Navigator 4 を使用し、Windows-31J のページを見る場合の話。
例えば、フォームに入力された文字列を取得して、何らかの処理をした後フォーム項目に再度設定する、というのを、しばしば見かける。

var s;

s = document.forms[0].elements[0].value;

// s に対して処理をいろいろ

document.forms[0].elements[1].value = s;

しかし、いわゆる「機種依存文字」が入力文字列に含まれていた場合、再度設定された内容を見ると、該当する文字が "?" (半角疑問符) に置き換えられている。これは、フォーム項目に再度する以外に、alert() や confirm() で表示した場合も同じだ。

背景

この現象の背景には、以下のような事実 (たぶん) がある。

  • JavaScript (というか ECMAScript) の仕様では、文字は Unicode で表す。
  • 他の文字コードから Unicode に変換する時、Unicode にない文字は REPLACEMENT CHARACTER (U+FFFD) に置き換えられる (ことがある)。
  • Netscape 4 では、フォームやダイアログは CP932 で処理されている。
  • Netscape 4 では、CP932←→Unicode の相互変換に、(Windows 標準のものではない) 独自の変換表を使っている。

何が起きるか

  1. フォームには、CP932 の任意の文字を入力できる (CP932 にない文字を入力すると、この時点で半角疑問符 "?" に置き換えられる)。
  2. JavaScript から、フォーム項目オブジェクトの value プロパティを参照すると、内容を Unicode に変換した上で、文字列 (String) が作成される。変換できなかった文字列は U+FFFD に置き換えられる。機種依存文字Netscape 4 の変換表に載っていない (っぽい) ので、問答無用で U+FFFD に置き換えられる。
  3. こうして得られた文字列をフォームに戻したり、alert() や confirm() で表示したりすると、再度 CP932 に変換される。この時、U+FFFD は CP932 にないため、半角疑問符 "?" に置き換えられる。

対象になる文字は?

MS-IME 2000 の文字パレットで言うと、以下のカテゴリの文字が化ける。

  • 囲み英数字/アラビア数字
  • 単位記号
  • 省略文字/囲み文字/年号
  • 外字
  • 漢字 3

参考

Unicode に変換された時点では、機種依存文字は U+FFFD になっているので、入力された文字列に機種依存文字が使われていないかを調べるには、String 内に U+FFFD があるか調べればいい。ただし、この時、どの機種依存文字が使われたかを知ることはできない (全部 U+FFFD になっちゃってるので)。
なお、Netscape機種依存文字をまったく扱えないわけではない。ページを Windows-31J で書いていて、JavaScript からいじらずに、そのままフォームを送信すると、機種依存文字でも (CP932 の範囲内であれば) そのまま、CP932 でのオクテット列が送信される。