web-dev-qa-db-ja.com

このコードが逆方向に書かれているのはなぜ「Hello World!」と表示されるのですか。

これは私がインターネット上で見つけたいくつかのコードです:

class M‮{public static void main(String[]a‭){System.out.print(new char[]
{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}    

このコードはHello World!を画面に表示します。あなたはそれが走るのを見ることができます ここpublic static void mainがはっきりと書かれているのがわかりますが、それは逆です。このコードはどのように機能しますか?どうやってこれをコンパイルするのですか?

編集:私はこのコードをIntellIJで試してみましたが、うまくいきました。しかし、なんらかの理由で、cmdと共にメモ帳++では機能しません。私はまだそれに対する解決策を見つけていないので、だれかがそうしたならば、以下にコメントしてください。

249
Shashwat Khanna

コードの表示方法を変更する見えない文字がここにあります。 Intellijでは、これらをコードを空の文字列("")にコピー&ペーストすることで見つけることができます。これは、それらをUnicodeエスケープで置き換え、それらの効果を取り除き、コンパイラが見る順序を明らかにします。

そのコピーペーストの出力は次のとおりです。

"class M\u202E{public static void main(String[]a\u202D){System.out.print(new char[]\n"+
        "{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}   "

ソースコード文字はこの順序で格納され、コンパイラはそれらをこの順序にある​​ものとして扱いますが、表示方法は異なります。

\u202E文字は、すべての文字が右から左に表示されるように強制されるブロックを開始する右から左へのオーバーライドであり、\u202Dは、ネストされたブロックを開始する左から右へのオーバーライドです。最初のオーバーライドをオーバーライドして、すべての文字を左から右の順に強制します。

Ergo、元のコードを表示するとき、class Mは通常どおりに表示されますが、\u202Eはそこからすべての表示順序を逆にして、\u202Dをすべて逆にします。 (正式には、\u202Dから行末記号までのすべてが2回反転されます。1回は\u202Dのため、もう1回は\u202Eのために反転されています。次の行の方向性は行末記号のために最初の行の方向性とは無関係に扱われるので、{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}は通常通り表示されます。

完全な(非常に複雑な、数十ページの)Unicode双方向アルゴリズムについては、 nicode Standard Annex#9 を参照してください。

245
Davis Broda

Unicode双方向アルゴリズム のため、外観が異なります。 Unicode双方向アルゴリズムがこれら2つのメタ文字の間にネストされている文字の外観を変更するために使用する、RLOとLROの2つの不可視文字があります。

その結果、視覚的逆順に見えますが、実際の文字メモリ内は逆にはなりません。あなたは結果を分析することができます ここ 。 JavaコンパイラはRLOとLROを無視し、それらを空白文字として扱います。これがコードがコンパイルする理由です。

Note 1:このアルゴリズムは、テキストエディタやブラウザでLTR文字(英語)とRTL文字(アラビア語、ヘブライ語など)の両方の文字を同時に視覚的に表示するために使用されます。双方向アルゴリズムの詳細については、Unicodeの Webサイト を参照してください。
Note 2:LROとRLOの正確な振る舞いは、アルゴリズムの 2.2節 で定義されています。

43
James Lawson

文字U+202Eは、コードを右から左に反映していますが、非常に巧妙です。 Mから隠れている、

"class M\u202E{..."

この背後にあるマジックをどのように見つけましたか?

さて、最初は「他の時間を失うことは冗談のようなものです」という難しい質問を見たとき、私はIDE( "IntelliJ")を開いてクラスを作成し、コードを過ぎて...コンパイルされたそれで、私はもっとよく見て、 "public static void"が後ろ向きであることを見たので、カーソルで行ってそして数文字を消します ...そしてどうなりますか? 文字が逆方向に消去されるようになったので、mmmmだと思いました。まれに...実行する必要があります。プログラムですが、最初に保存するにはが必要でした...それが見つかったときはでした!ファイルを保存できませんでした。私のIDEは、ある文字に対して異なるエンコーディングがあると言っていたので、それがどこにあるかを指摘していました、だから私は仕事をすることができる特別な文字のためにグーグルで研究を始めます、そしてそれはそれです:)

少し

unicode双方向アルゴリズム、および関連するU+202E説明

ユニコード規格は、論理的順序として知られるメモリ表現順序を規定している。テキストが横線で表示されている場合、ほとんどのスクリプトは左から右へ文字を表示します。ただし、表示される水平テキストの自然な順序が右から左になるような、いくつかのスクリプト(アラビア語やヘブライ語など)があります。すべてのテキストが一様な水平方向を持つ場合、表示テキストの順序は明確になります。

しかし、これらの右から左へのスクリプトは左から右に書かれる数字を使用するので、テキストは実際には双方向です:右から左へのテキストと左から右へのテキストの混合。数字に加えて、英語や他の文字からの埋め込まれた単語も左から右へ書かれており、これも双方向のテキストを生成します。明確な指定がないと、テキストの水平方向が一様でない場合に表示される文字の順序を決定する際にあいまいさが生じる可能性があります。

この附属書は双方向のUnicodeテキストの方向性を決定するために使用されるアルゴリズムを記述する。このアルゴリズムは、現在多くの既存の実装で現在採用されている暗黙のモデルを拡張し、特別な状況のために明示的なフォーマット文字を追加します。ほとんどの場合、正しい表示順序を得るためにテキストに追加情報を含める必要はありません。

ただし、双方向テキストの場合は、暗黙的な双方向の順序では理解可能なテキストを生成するのに十分ではない場合があります。このような場合に対処するために、レンダリング時の文字の順序を制御するために、最小限の方向性書式設定文字が定義されています。これにより、読みやすいインターチェンジの表示順序を正確に制御でき、ファイル名やラベルなどの単純な項目に使用されるプレーンテキストを常に表示のために正しく順序付けることができます。

なぜ this のようなアルゴリズムを作成するのでしょうか。

双方向アルゴリズムでは、アラビア文字またはヘブライ文字のシーケンスを右から左に順番にレンダリングできます。

P.S .:それが最善の解決策ではないことはわかっていますが、最初に問題を解決するのは楽しかったです。

27

言語仕様の第3章 は、Javaプログラムに対して字句変換がどのように行われるかを詳細に説明することによって説明を提供します。問題にとって最も重要なこと

プログラムはUnicode(3.1)で書かれていますが、字句翻訳が提供されているので(3.2)、Unicodeエスケープ(3.3)を使って含めることができますASCII文字のみを使用する任意のUnicode文字。

そのため、プログラムはUnicode文字で書かれており、ファイルエンコーディングがUnicode文字をサポートしていない場合は\uxxxxを使用してプログラムをエスケープすることができます。この場合に存在するUnicode文字の1つは\u202Eです。スニペットには視覚的には表示されませんが、ブラウザのエンコードを切り替えようとすると、隠された文字が表示されることがあります。

したがって、字句変換はクラス宣言になります。

class M\u202E{

つまり、クラス識別子はM\u202Eです。 specification はこれを有効な識別子と見なします。

Identifier:
    IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
IdentifierChars:
    JavaLetter {JavaLetterOrDigit}

「Javaの文字または数字」は、メソッドCharacter.isJavaIdentifierPart(int)がtrueを返す文字です。

4
manouti