これは私がインターネット上で見つけたいくつかのコードです:
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と共にメモ帳++では機能しません。私はまだそれに対する解決策を見つけていないので、だれかがそうしたならば、以下にコメントしてください。
コードの表示方法を変更する見えない文字がここにあります。 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 を参照してください。
Unicode双方向アルゴリズム のため、外観が異なります。 Unicode双方向アルゴリズムがこれら2つのメタ文字の間にネストされている文字の外観を変更するために使用する、RLOとLROの2つの不可視文字があります。
その結果、視覚的逆順に見えますが、実際の文字メモリ内は逆にはなりません。あなたは結果を分析することができます ここ 。 JavaコンパイラはRLOとLROを無視し、それらを空白文字として扱います。これがコードがコンパイルする理由です。
Note 1:このアルゴリズムは、テキストエディタやブラウザでLTR文字(英語)とRTL文字(アラビア語、ヘブライ語など)の両方の文字を同時に視覚的に表示するために使用されます。双方向アルゴリズムの詳細については、Unicodeの Webサイト を参照してください。
Note 2:LROとRLOの正確な振る舞いは、アルゴリズムの 2.2節 で定義されています。
文字U+202E
は、コードを右から左に反映していますが、非常に巧妙です。 Mから隠れている、
"class M\u202E{..."
この背後にあるマジックをどのように見つけましたか?
さて、最初は「他の時間を失うことは冗談のようなものです」という難しい質問を見たとき、私はIDE( "IntelliJ")を開いてクラスを作成し、コードを過ぎて...コンパイルされたそれで、私はもっとよく見て、 "public static void"が後ろ向きであることを見たので、カーソルで行ってそして数文字を消します ...そしてどうなりますか? 文字が逆方向に消去されるようになったので、mmmmだと思いました。まれに...実行する必要があります。プログラムですが、最初に保存するにはが必要でした...それが見つかったときはでした!ファイルを保存できませんでした。私のIDEは、ある文字に対して異なるエンコーディングがあると言っていたので、それがどこにあるかを指摘していました、だから私は仕事をすることができる特別な文字のためにグーグルで研究を始めます、そしてそれはそれです:)
少し
unicode双方向アルゴリズム、および関連するU+202E
、 説明 :
ユニコード規格は、論理的順序として知られるメモリ表現順序を規定している。テキストが横線で表示されている場合、ほとんどのスクリプトは左から右へ文字を表示します。ただし、表示される水平テキストの自然な順序が右から左になるような、いくつかのスクリプト(アラビア語やヘブライ語など)があります。すべてのテキストが一様な水平方向を持つ場合、表示テキストの順序は明確になります。
しかし、これらの右から左へのスクリプトは左から右に書かれる数字を使用するので、テキストは実際には双方向です:右から左へのテキストと左から右へのテキストの混合。数字に加えて、英語や他の文字からの埋め込まれた単語も左から右へ書かれており、これも双方向のテキストを生成します。明確な指定がないと、テキストの水平方向が一様でない場合に表示される文字の順序を決定する際にあいまいさが生じる可能性があります。
この附属書は双方向のUnicodeテキストの方向性を決定するために使用されるアルゴリズムを記述する。このアルゴリズムは、現在多くの既存の実装で現在採用されている暗黙のモデルを拡張し、特別な状況のために明示的なフォーマット文字を追加します。ほとんどの場合、正しい表示順序を得るためにテキストに追加情報を含める必要はありません。
ただし、双方向テキストの場合は、暗黙的な双方向の順序では理解可能なテキストを生成するのに十分ではない場合があります。このような場合に対処するために、レンダリング時の文字の順序を制御するために、最小限の方向性書式設定文字が定義されています。これにより、読みやすいインターチェンジの表示順序を正確に制御でき、ファイル名やラベルなどの単純な項目に使用されるプレーンテキストを常に表示のために正しく順序付けることができます。
なぜ this のようなアルゴリズムを作成するのでしょうか。
双方向アルゴリズムでは、アラビア文字またはヘブライ文字のシーケンスを右から左に順番にレンダリングできます。
P.S .:それが最善の解決策ではないことはわかっていますが、最初に問題を解決するのは楽しかったです。
言語仕様の第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を返す文字です。