実行 - java 文字コード 変換 ライブラリ
特定のUnicode文字を使用してコメントでJavaコードを実行できるのはなぜですか? (6)
@zwolは、これが設計ミスであることに同意します。 しかし、私はさらに批判的です。
\u
エスケープは、文字列および文字リテラルで役立ちます。
それが存在するべき唯一の場所です。
\n
などの他のエスケープと同じ方法で処理する必要があります。
"\u000A"
は
正確に
"\n"
意味します。
コメントに
\uxxxx
意味はまったくありません。誰も読むことができません。
同様に、プログラムの他の部分で
\uxxxx
を使用する意味はありません。
唯一の例外はおそらく、いくつかの非ASCII文字を含むように強制されているパブリックAPIにあるでしょう-最後に見たのは何ですか?
デザイナーには1995年に理由がありましたが、20年後、これは間違った選択のようです。
(読者への質問-この質問はなぜ新しい票を獲得し続けるのですか?この質問はどこか人気のあるリンクですか?)
次のコードは、出力「Hello World!」を生成します (いいえ、実際に試してみてください)。
public static void main(String... args) {
// The comment below is not a typo.
// \u000d System.out.println("Hello World!");
}
これは、JavaコンパイラがUnicode文字
\u000d
を新しい行として解析し、
\u000d
ように変換されるためです。
public static void main(String... args) {
// The comment below is not a typo.
//
System.out.println("Hello World!");
}
したがって、コメントは「実行」されます。
これは悪意のあるコードや悪意のあるプログラマーが想像できるものを「隠す」ために使用できるため 、コメントで許可 されているのは なぜ ですか?
Java仕様でこれが許可されているのはなぜですか?
Unicodeエスケープが実装された理由に答えることができるのは、仕様を書いた人だけです。
これのもっともらしい理由は、BMP全体をJavaソースコードの可能な文字として許可したいという要望があったことです。 ただし、これには問題があります。
- 任意のBMP文字を使用できるようにします。
- BMP文字を合理的に簡単に入力できるようにしたいと考えています。 これを行う方法は、Unicodeエスケープを使用することです。
- 字句の仕様は、人間が読み書きしやすく、実装も合理的に簡単にする必要があります。
これは、Unicodeエスケープが乱れた場合、非常に困難です。新しいレクサールールが大量に作成されます。
簡単な方法は、2つのステップで字句解析を行うことです。最初にすべてのUnicodeエスケープを検索して、それが表す文字に置き換え、次にUnicodeエスケープが存在しないかのように結果のドキュメントを解析します。
これの利点は、指定が簡単であるため、仕様がより簡単になり、実装が簡単になることです。
欠点は、まあ、あなたの例です。
これは、Javaの元の設計にまでさかのぼる意図的な設計選択でした。
「誰がUnicodeをコメントでエスケープしたいのか」と尋ねる人々にとって、私は彼らが母国語がラテン文字セットを使用している人々であると思います。 言い換えれば、Javaプログラムで合法な場合、最も一般的にはコメントや文字列で、人々が任意のUnicode文字を使用できるということは、Javaの元の設計に固有のものです。
おそらく、ソーステキストを表示するために使用されるプログラム(IDEなど)の欠点は、そのようなプログラムがUnicodeエスケープを解釈できず、対応するグリフを表示できないことです。
これはまだ対処されていないので、ここで、他のソースコード処理の前にUnicodeエスケープの変換が行われる理由を説明します。
その背後にあるアイデアは、異なる文字エンコーディング間のJavaソースコードのロスレス変換を可能にするというものでした。 今日、Unicodeのサポートが広く行われていますが、これは問題のようには見えませんが、当時は西側の開発者がアジア人のキャラクターを含むアジア人の同僚からソースコードを受け取り、変更を加えることは容易ではありませんでした(コンパイルとテストを含む)、結果を返送しますが、いずれも損傷を与えることはありません。
したがって、Javaソースコードは任意のエンコーディングで記述でき、識別子、文字、および
String
リテラルとコメント内の幅広い文字を使用できます。
次に、ロスレスで転送するために、ターゲットエンコーディングでサポートされていないすべての文字がUnicodeエスケープに置き換えられます。
これは可逆的なプロセスであり、興味深い点は、変換ルールが依存していないため、Javaソースコードの構文について何も知る必要のないツールで変換できることです。 これは、コンパイラ内の実際のUnicode文字への変換がJavaソースコードの構文とは独立して行われるために機能します。 ソースコードの意味を変えることなく、双方向で任意の数の翻訳ステップを実行できることを意味します。
これは、言及されていない別の奇妙な機能の理由です:
\uuuuuuxxxx
構文:
翻訳ツールが文字をエスケープし、すでにエスケープされたシーケンスであるシーケンスに遭遇した場合、追加の
u
をシーケンスに挿入して、
\ucafe
を
\uucafe
変換する
\uucafe
ます。
意味は変わりませんが、他の方向に変換する場合、ツールは1つの
u
を削除し、単一の
u
を含むシーケンスのみをUnicode文字で置き換える必要があります。
このようにして、Unicodeエスケープでさえ、前後に変換するときに元の形式で保持されます。
誰もその機能を使用したことはないと思います…
私は自分自身を助けることができず、まだそれを見たことがないという理由だけで、間違っている隠された前提が含まれているため、質問が無効である、つまりコードがコメント!
Javaソースコードでは、\ u000dはASCII CR文字とあらゆる点で同等です。 それはどこでも、それがどこにいても、シンプルでシンプルな行末です。 質問の書式設定は誤解を招く恐れがあります。実際に構文的に対応する文字列は次のとおりです。
public static void main(String... args) {
// The comment below is no typo.
//
System.out.println("Hello World!");
}
したがって、最も正確な答えは次のとおりです。コードはコメントに含まれていないため実行されます。 次の行にあります。 「コメント内のコードの実行」は、期待どおりにJavaで許可されていません。
混乱の多くは、構文ハイライターとIDEがこの状況を考慮に入れるのに十分なほど洗練されていないという事実に起因しています。
Unicodeエスケープをまったく処理しないか、
javac
ようにコードを解析する前ではなく解析した後に処理します。
\u
エスケープは、プログラムがトークン化さ
れる前に
対応するUnicode文字
に
一様に変換されるため、
\u000d
エスケープはコメントを終了します。
//
代わりに
\u0057\u0057
使用してコメントを
開始
することもできます。
これはIDEのバグであり、
\u000d
がコメントを終了することを明確にするために行を構文強調表示する必要があります。
これは、言語の設計エラーでもあります。
今は修正できません。依存しているプログラムが壊れてしまうからです。
\u
エスケープは、「意味がある」コンテキスト(文字列リテラルと識別子、おそらくどこにもない)でのみコンパイラーによって対応するUnicode文字に変換されるか、U + 0000で文字を生成することを禁止されるべきです。 007F範囲、またはその両方。
これらのセマンティクスのいずれかは、
\u
エスケープが便利な場合を妨げることなく、コメントが
\u000d
エスケープで終了するのを防ぎます。これには、コメント内でのコメントをエンコードする方法として
\u
エスケープの使用が
含まれ
ます-ラテンスクリプト。テキストエディターは、コンパイラが行うよりも
\u
エスケープが重要な場所をより広範囲に表示できるためです。
(ただし、
どの
コンテキストでも
\u
エスケープを対応する文字として表示するエディターまたはIDEを知りません。)
Cファミリにも同様の設計エラーがあり、 1 はコメント境界が決定される前にバックスラッシュと改行が処理されるため、たとえば
// this is a comment \
this is still in the comment!
これを取り上げて、この特定の設計エラーを簡単に犯すことができることを説明し、コンパイラープログラマーが考える方法をトークン化と構文解析について熟知している場合、修正するには手遅れになるまでエラーであることに気付かないトークン化と解析について。 基本的に、正式な文法をすでに定義していて、誰かが構文上の特殊なケースを考え出した場合-トライグラフ、バックスラッシュ-改行、ASCIIに制限されたソースファイル内の任意のUnicode文字をエンコードするトークナイザーの 前に 変換パスを追加して、トークナイザーを再定義し、その特殊なケースを使用する意味がある場所に注意を向けます。
1 ぺダントの場合:Cのこの側面は100%意図的であり、これを構成するわけではないという理由で、パンチされたカードに任意の長い行のコードを機械的に強制適合できることを知っています。 まだ間違った設計決定でした。