거꾸로 작성된이 코드가“Hello World!”를 인쇄하는 이유는 무엇입니까?


261

인터넷에서 찾은 코드는 다음과 같습니다.

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 ++에서는 작동하지 않습니다. 나는 여전히 그것에 대한 해결책을 찾지 못했습니다. 그렇다면 누군가 아래에 의견을 적으십시오.


38
이건 재밌어요 ... RTL 지원과 관련이 있습니까?
유진 Sh.

12
유니 코드 문자 # 8237이 있습니다. 바로 후 M도 후 []a: fileformat.info/info/unicode/char/202d/index.htm 이 왼쪽에서 오른쪽으로 OVERRIDE라고
Riiverside

45
의무적 인 xkcd : xkcd.com/1137
Pac0

4
마우스를 사용하여 코드 스 니펫을 선택하면 여기에서 진행중인 작업을 매우 쉽게 확인할 수 있습니다.
Andreas Rejbrand

14
niam diov citats cilbup라틴어 속담처럼 들립니다.
Mick Mnemonic

답변:


250

코드 표시 방법을 변경하는 보이지 않는 문자가 여기에 있습니다. 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를 참조하십시오 .


컴파일러 (디스플레이 루틴과 반대)가 이러한 유니 코드 문자 자체로 수행하는 작업에 대해서는 설명하지 않습니다. 나는 그것들을 완전히 무시하거나 공백으로 취급하거나 실제로 소스 코드에 기여하는 것으로 해석 할 수 있습니다. 여기서 Java 규칙을 모르지만 사용되지 않는 식별자의 끝에 배치된다는 사실은 후자가 될 수 있으며 유니 코드 문자는 실제로 식별자 이름의 일부임을 나타냅니다.
Marc van Leeuwen

이것은 C #에서 관심없이 동일한 방식으로 작동합니까?
IanF1

14
@ IanF1 컴파일러 / 인터프리터가 RTL 및 LTR 문자를 공백으로 계산하는 모든 언어에서 작동합니다. 그러나 다음 코드를 작성하는 다음 사람의 정신을 중요하게 생각한다면 프로덕션 코드에서는 절대로 그렇게하지 마십시오 .
wizzwizz4

2
즉, "코드를 유지 관리하는 사람이 귀하의 거주지를 아는 폭력적인 정신병자 인 것처럼 항상 코드를 작성하십시오." @ IanF1입니다. 또는 "아직 코드를 관리하는 사람이 스택 오버플로의 원래 작성자로 이름을 밝히고 수치스럽게 생각하는 것처럼 항상 코드를 작성하십시오."
코디 그레이

43

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

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

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


그러한 능력의 목적은 무엇입니까?
유진 Sh.

6
이러한 문자는 때때로 아랍어와 히브리어를 시각적으로 올바르게 렌더링하는 데 필요합니다. 이 언어는 오른쪽에서 왼쪽 (RTL)으로 읽고 씁니다. 읽고 쓰는 첫 번째 문자가 오른쪽에 나타납니다 . 자세한 내용은 여기를 참조 하십시오 .
James Lawson

아랍어와 히브리어 문자는 본질적으로 RTL입니다. 명시 적으로 재정의하지 않아도 RTL로 표시되며 근처의 다른 특정 문자의 순서를 자동으로 되돌릴 수도 있습니다.
user2357112는 Monica

이 페이지 여기가 재정의가 필요한 경우에 대해 설명합니다. @ user2357112가 맞습니다. 거의 필요하지 않습니다. 실제로 문장 부호, 따옴표 및 숫자가있는 경우 이러한 특수 문자는 "중립"으로 간주됩니다. 말씀을 읽고 문맥을 이해할 수없는 컴퓨터의 경우, LTR 또는 RTL로 처리 할 것인지 불분명하지만, 쌍방향 알고리즘을 선택하는 몇 가지 순서를. 때때로 그것은 "잘못된다"그리고 당신은 "수정"하기 위해이 무시 문자를 사용해야합니다.
James Lawson

3
또한 U + 202E 및 U + 202D는 공백으로 간주되지 않습니다. Java는 ASCII 공간, 가로 탭, 용지 공급 및 CR / LF / CRLF 만 공백으로 간주합니다 . 그들은 전적으로 실제로 식별자의 일부있어 M\u202E하고 a\u202D있지만, 그 식별자는 동등으로 처리 한 것으로 나타났습니다 M하고 a. (JLS는 이것을 잘 설명하지 않습니다.)
user2357112는 Monica를 지원합니다

28

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

"class M\u202E{..."

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

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

조금

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

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

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

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

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

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

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


4

언어 사양의 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를 리턴 하는 문자입니다 .


죄송하지만이 기능은 이전 버전입니다. 소스 코드에는 이스케이프가 없습니다. 당신은 그것이 어떻게 쓰여 졌는지 설명하고 있습니다. 그리고 "M"이라는 클래스 (한 문자 만)로 컴파일합니다.
Tom Blodget

@TomBlodget 실제로 그러나 요점 (사실 사양에서 강조 표시 된)은 컴파일러가 원시 유니 코드 문자를 처리 할 수도 있다는 것입니다. 그것은 실제로 전체 설명입니다. 이스케이프 변환은 추가 정보 일 뿐이며이 경우와 직접 관련이 없습니다. 컴파일 된 클래스는 RTL 스위치 문자가 어떻게 든 컴파일러에 의해 버려지기 때문이라고 생각합니다. 이것이 예상되는지 보려고 노력할 것이지만 어휘 변환 단계 이후에 발생한다고 생각합니다.
M Anouti
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.