Tategoto is here.
Problem Of Yen-Escape

[← TpAddYenWith TeraPadMenuTop

last updated: 2009.10.19

エスケープシーケンスについて

エスケープシーケンスとは

例えば CGI のスクリプティング言語として有名な perl では、「print」 という、指定した文字をそのまま表示する命令があります。 例えば、

print "こんにちは。はじめまして。";

と書くと、

こんにちは。はじめまして。

と表示されます。 ここで、

print "こんにちは。\nはじめまして。";

というように 「\n」 をはさんで書くと、

こんにちは。
はじめまして。

と表示されます。改行されていますね。 「n」 はただの n なのに、その直前に 「\」 をつけることによって、改行するという動作に変わっています。 そして、「n」 そのものは出力されていません。

この 「\n」 のように、ある特定の文字の前に 「\」 をつけることによって特別な操作が行われるようにすることを、エスケープシーケンスといいます。

※ Perl、csh、C/C++ のエスケープシーケンス機能は厳密に言うと、それぞれ微妙に違います。が、似たようなものです (笑)

未定義エスケープシーケンスの扱い

ところで、「\」 文字や 「"」 文字を表示したいという場合にはどうすればいいのでしょうか。

「\」 をただそのまま書いても、エスケープシーケンスの開始とみなされてしまいます。 また、「"」 を書こうものなら、その場で文字列が途切れてしまい、文法エラーになってしまいます。

print "これ \ は、円マークです。";
※ 「\」 は無視される

print "これ " は、ダブルクォーテーションです。";
※ "これ " で文字列が閉じてしまうのに、その次にいきなり 「は、〜」 と始まるので文法エラー

実は 「\」 エスケープは、その次に指定された文字がエスケープシーケンスとして無効である場合には、「\」 を取り除いた上でその文字をそのまま表示します。 なのでこの場合は、

print "これ \\ は、円マークです。";
print "これ \" は、ダブルクォーテーションです。";
※ 「\"」 では文字列を閉じたことにはならない

と書きます。そうするとちゃんと

これ \ は、円マークです。
これ " は、ダブルクォーテーションです。

と表示されます。

Shift_JIS の 「\」 エスケープ問題について

Shift_JIS では何も悪い事をしていなくても問題が発生することがある

「\」 という文字をエスケープシーケンスの開始とみなす 「日本語未対応」 の処理系の場合、Shift_JIS の 2 バイト文字 (いわゆる全角文字) を扱わせると問題が出てくることがあります。 例えば

print "これからの予定";

と書くと、

これからの嵐

と表示されます。 なんか文字が変わってしまっていますね。。
また、

print "貼り付け機能";

とか書くと、今度はいきなり文法エラーになってしまい、プログラムの実行すらできなくなります・・・うー。

Shift_JIS で問題が発生する理由

このような問題が発生する理由は、Shift_JIS には、2 バイト目に 「\」 と同じ文字コードを含む文字がいくつかあるためです。 日本語未対応の処理系では、ひらがなや漢字などの 2 バイト文字は 2 文字として扱ってしまうため、日本語で表示した時に 「\」 が見えなくても、「\」 が指定されたと勘違いします (笑)

※ 日本語対応の処理系では、2 バイト文字でも 1 文字として扱うので、特に問題はありません。

ちなみに、どの文字に含まれているかは、英字フォントで表示させてみればわかります。

日本語フォント こ れ か ら の 予 定 貼 り 付 け 機 能
英字フォント ,+ ,e ,c ,c ,I -\ 'e "\ ,e .t ,~ <@ "\

※ 表示できない文字は、それに近い ASCII 文字で書いてみました。
※ 英字フォントでは、「\」 は 「\」 (バックスラッシュ) で表示されます。

という事で、先ほどの print 命令は、(「日本語未対応の処理系」 から見ると) それぞれ

print ",+,e,c,c,I-\'e"; # これからの予定
print ""\,e.t,~<@"\"; # 貼り付け機能

と書いたことになります。 で、上記の通り、「\」 エスケープは、その次に指定された文字がエスケープシーケンスとして無効である場合には、「\」 を取り除いた上でその文字をそのまま表示するために、「\」 が取り除かれる形になってしまうのです。

ちなみになぜ 「予定」 → 「嵐」 なのかと言うと、それは文字コードを調べてみればわかります。

予 → [975C]
定 → [92E8]

なので、「予定」 を 1 バイトずつ表すと、

[97] [5C] [92] [E8]

になります。ここで、「\」 (文字コード 5C) を取り除くと、

[97] [92] [E8]

となります。で、

[9792] → 嵐

となるわけです。

※ しかし、「予定」 → 「嵐」 って・・・よりによって 「嵐」 って・・・何かの暗示でしょーか??
※ っていうか、[E8] が余ってるなあ・・・。不気味だなあ・・・。。

また、「貼り付け機能」 の方は、文字列を閉じるつもりで書いた 「"」 が文字列の一部として扱われてしまい、

print ""\,e.t,~<@"\"; # 貼り付け機能
※ 「\"」 では文字列を閉じたことにはならない

そのため文字列を全然閉じていないことになるので文法エラーとなります。

Shift_JIS の 「\」 エスケープ問題の回避方法

この問題を回避するには、いくつかの方法があります。

1. 文字コードを EUC-JP にする

これが一般的な回避方法です。 EUC-JP には、「エスケープコードを含む 2 バイト文字」 が存在しないので、この問題は発生しません。
※ 中には、こういう理由があると知らずに EUC-JP にしてる人も・・・。
※ ちょうど TeraPad も EUC-JP での保存に対応している事だし・・・。

ただし、この方法では、Shift_JIS での出力が要求されるプログラムには対応できません。
※ 例えば、i-mode 対応の CGI とか。。

2. プログラムの中に、日本語は一切記述しない

この問題が発生するのは、処理系がプログラムを解釈する時だけです。 なので、外部にメッセージを定義したファイルを用意して、そこから読み込むという具合にすれば、化けたりしません。

もちろん、そういう風にプログラムを作るのは面倒です。 ええ、そりゃあもう。

3. はなから 「エスケープコードを含む 2 バイト文字」 を使わない

そういう問題のある文字を使っていなければ、当然問題は起こりません。 が・・・かなりの頻度で使われる文字もいくつか含んでいたり・・・。
一般に 「ダメ文字」 と呼ばれる文字です。

― [815C] [835C]Ы [845C]IX [875C] [895C]浬 [8A5C] [8B5C]
圭 [8C5C] [8D5C]蚕 [8E5C] [8F5C] [905C]曾 [915C]箪 [925C]
[935C] [945C] [955C] [965C] [975C]禄 [985C] [995C]
喀 [9A5C]媾 [9B5C]彌 [9C5C]拿 [9D5C]杤 [9E5C]歃 [9F5C]濬 [E05C]
畚 [E15C]秉 [E25C]綵 [E35C]臀 [E45C]藹 [E55C]觸 [E65C]軆 [E75C]
鐔 [E85C]饅 [E95C]鷭 [EA5C]x [ED5C]x [EE5C]\ [FA5C]\ [FB5C]

※ 抜けがあるかもしれません・・・。

4. エスケープコードを含む 2 バイト文字の後ろに 「¥」 文字を挿入する

要は、「\」 が勝手に消えてしまうのが問題なわけであって、「\」 が消えないようにその後ろにもう一つ 「\」 を置いてやると、この問題は回避できます。

print "これからの予\定";
print "貼\り付け機能\";

これを自動で行うのが、今回リリースの 「TpAddYen」 です♪

[← TpAddYenWith TeraPadMenuTop

©2000-2008 Tategoto, all right reserved.
mailto:tateharpy@gmail.com