[java] 거꾸로 작성된이 코드가“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와 함께 notepad ++에서는 작동하지 않습니다. 나는 여전히 그것에 대한 해결책을 찾지 못했습니다. 그렇다면 누군가 아래에 의견을 적으십시오.



답변

코드 표시 방법을 변경하는 보이지 않는 문자가 여기에 있습니다. Intellij에서는 코드를 빈 문자열 ( "") 에 복사하여 붙여 넣을 수 있습니다.이 문자열 은 유니 코드 이스케이프로 대체되어 영향을 제거하고 컴파일러가 보는 순서를 나타냅니다.

해당 복사 붙여 넣기의 출력은 다음과 같습니다.

"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줄 종결 자 까지의 모든 내용은 로 인해 한 번 두 번 반전 \u202D되고 으로 인해 한 번만 텍스트의 나머지 부분이 바뀌어 한 번 반전 되므로이 \u202E텍스트는 줄 대신 중간에 표시됩니다.) 다음 줄의 방향성은 줄 종결 자로 인해 첫 줄과 독립적으로 처리되므로 {'H','e','l','l','o',' ','W','o','r','l','d','!'});}}정상적으로 표시됩니다.

전체 (매우 복잡한 수십 페이지 길이) 유니 코드 양방향 알고리즘에 대해서는 유니 코드 표준 부록 # 9를 참조하십시오 .


답변

Unicode Bidirectional Algorithm 때문에 다르게 보입니다 . 유니 코드 양방향 알고리즘 이이 두 메타 문자 사이에 중첩 된 문자 의 시각적 모양 을 변경하는 데 사용하는 두 개의 보이지 않는 RLO 및 LRO 문자가 있습니다.

결과적 으로 시각적으로 역순 으로 보이지만 메모리 의 실제 문자 반전되지 않습니다. 여기 에서 결과를 분석 할 수 있습니다 . Java 컴파일러는 RLO 및 LRO를 무시하고 공백으로 처리하므로 코드가 컴파일됩니다.

참고 1 :이 알고리즘은 텍스트 편집기와 브라우저에서 LTR 문자 (영어)와 RTL 문자 (예 : 아랍어, 히브리어)를 동시에 시각적으로 표시하기 위해 사용되므로 “bi”방향입니다. 양방향 알고리즘에 대한 자세한 내용은 Unicode 웹 사이트를 참조하십시오 .
참고 2 : LRO 및 RLO의 정확한 동작은 알고리즘 2.2 에 정의되어 있습니다.


답변

캐릭터 U+202E는 코드를 오른쪽에서 왼쪽으로 미러링하지만 매우 영리합니다. M부터 시작해서 숨겨져 있고

"class M\u202E{..."

이 뒤에 숨겨진 마법을 어떻게 찾았 습니까?

글쎄, 처음에 내가 힘든 질문을 보았을 때, “다른 사람을 잃는 것은 일종의 농담입니다.”하지만 IDE ( “IntelliJ”)를 열고 클래스를 만들고 코드를 지나서 … 그리고 그것은 컴파일되었습니다 ! 그래서 나는 더 나은 모습을 보았고 “공공 정적 공백”이 뒤로 있다는 것을 알았으므로 커서로 거기에 가서 몇 개의 문자를 삭제했습니다 … 그리고 어떻게됩니까? 문자가 뒤로 지우기 시작 했기 때문에 mmm을 생각했습니다 …. 드문 … 실행해야합니다 … 프로그램을 계속 진행하지만 먼저 저장해야했습니다 … 그리고 그 때였습니다 그것을 발견! . IDE에서 일부 문자에 대해 다른 인코딩이 있다고 말하고 파일이 어디에 있는지 알려주므로 파일을 저장할 수 없습니다, 그래서 나는 일을 할 수있는 특별한 숯에 대해 Google에서 연구를 시작합니다.

조금

Unicode Bidirectional Algorithm과 U+202E관련된 간단한 설명 :

유니 코드 표준은 논리적 순서로 알려진 메모리 표현 순서를 규정합니다. 텍스트가 가로줄로 표시되면 대부분의 스크립트는 왼쪽에서 오른쪽으로 문자를 표시합니다. 그러나 표시되는 가로 텍스트의 자연 순서가 오른쪽에서 왼쪽 인 여러 스크립트 (예 : 아랍어 또는 히브리어)가 있습니다. 모든 텍스트의 가로 방향이 균일하면 표시 텍스트의 순서가 명확합니다.

그러나 이러한 오른쪽에서 왼쪽으로 쓰는 스크립트는 왼쪽에서 오른쪽으로 쓴 숫자를 사용하기 때문에 텍스트는 실제로 양방향입니다. 오른쪽에서 왼쪽 및 왼쪽에서 오른쪽으로 텍스트가 혼합되어 있습니다. 숫자 외에도 영어 및 기타 스크립트의 내장 단어가 왼쪽에서 오른쪽으로 작성되어 양방향 텍스트도 생성합니다. 명확한 지정이 없으면 텍스트의 가로 방향이 균일하지 않은 경우 표시되는 문자의 순서를 결정하는 데 모호성이 발생할 수 있습니다.

이 부록은 양방향 유니 코드 텍스트의 방향성을 결정하는 데 사용되는 알고리즘을 설명합니다. 이 알고리즘은 여러 기존 구현에서 현재 사용하는 암시 적 모델을 확장하고 특수한 상황에 대한 명시 적 서식 문자를 추가합니다. 대부분의 경우 올바른 표시 순서를 얻기 위해 텍스트에 추가 정보를 포함 할 필요가 없습니다.

그러나 양방향 텍스트의 경우 암시 적 양방향 순서가 이해하기 어려운 텍스트를 생성하기에 충분하지 않은 상황이 있습니다. 이러한 경우를 처리하기 위해 렌더링 될 때 문자 순서를 제어하기 위해 최소 방향 서식 문자 세트가 정의됩니다. 이를 통해 읽기 쉬운 교환을위한 디스플레이 순서를 정확하게 제어 할 수 있으며 파일 이름이나 레이블과 같은 간단한 항목에 사용되는 일반 텍스트를 항상 올바르게 표시 할 수 있습니다.

이런 알고리즘을 만들 까요?

bidi 알고리즘은 오른쪽에서 왼쪽으로 차례로 일련의 아랍어 또는 히브리어 문자를 렌더링 할 수 있습니다.


답변

언어 사양의 3 장 에서는 Java 프로그램에서 어휘 변환이 수행되는 방식을 자세히 설명하여 설명합니다. 질문에서 가장 중요한 것은 :

프로그램은 유니 코드 (§3.1)로 작성 되지만, 어휘 변환 (§3.2)이 제공되므로 유니 코드 이스케이프 (§3.3)를 사용하여 ASCII 문자 만 사용하는 유니 코드 문자를 포함 할 수 있습니다.

따라서 프로그램은 유니 코드 문자로 작성되며 \uxxxx파일 인코딩이 유니 코드 문자를 지원하지 않는 경우 이를 사용하여 프로그램 을 이스케이프 처리 할 수 ​​있습니다 .이 경우 적절한 문자로 변환됩니다. 이 경우 존재하는 유니 코드 문자 중 하나는 \u202E입니다. 스 니펫에는 시각적으로 표시되지 않지만 브라우저 인코딩을 전환하려고하면 숨겨진 문자가 나타날 수 있습니다.

따라서 어휘 변환으로 클래스 선언이 발생합니다.

class M\u202E{

이는 클래스 식별자가임을 의미합니다 M\u202E. 사양은 유효한 식별자로 이것을 고려 :

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

“자바 문자”는 메소드 Character.isJavaIdentifierPart(int)가 true를 리턴 하는 문자입니다 .


답변