Почему этот код, написанный в обратном порядке, печатает "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. Я до сих пор не нашел для этого решения, поэтому, если кто-нибудь это сделает, прокомментируйте ниже.

Ответ 1

Здесь есть невидимые символы, которые изменяют способ отображения кода. В 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, который является слева направо, right override, запуск вложенного блока, где все символы принудительно влево-вправо, переопределяя первое переопределение.

Ergo, когда он отображает исходный код, обычно отображается class M, но \u202E меняет порядок отображения всего оттуда до \u202D, что снова отменяет все. (Формально все от \u202D до терминатора линии обращается дважды, один раз из-за \u202D и один раз, когда остальная часть текста отменяется из-за \u202E, поэтому этот текст появляется в середине линии, а не конца.) Следующая направленность линии обрабатывается независимо от первого из-за терминатора линии, поэтому {'H','e','l','l','o',' ','W','o','r','l','d','!'});}} отображается нормально.

Для полного (чрезвычайно сложного, десятка страниц) двунаправленного алгоритма Unicode см. Стандартное приложение Unicode № 9.

Ответ 2

Это выглядит по-другому из-за Двунаправленный алгоритм Unicode. Есть два невидимых символа RLO и LRO, которые использует двунаправленный алгоритм Unicode, чтобы изменить визуальный внешний вид символов, вложенных между этими двумя метасимволами.

В результате визуально они выглядят в обратном порядке, но фактические символы в памяти не меняются. Вы можете проанализировать результаты здесь. Компилятор Java будет игнорировать RLO и LRO и рассматривать их как пробельные символы, поэтому компиляция кода.

Примечание 1: Этот алгоритм используется текстовыми редакторами и браузерами для визуального отображения символов как символов LTR (английский), так и RTL-символов (например, Арабский, иврит) вместе в одно и то же время - следовательно, "би" - направление. Вы можете больше узнать о двунаправленном алгоритме на странице Unicode .
Примечание 2: Точное поведение LRO и RLO определено в Раздел 2.2 Алгоритм.

Ответ 3

Символ U+202E отражает код справа налево, но он очень умный. Является скрытым, начиная с M,

"class M\u202E{..."

Как я нашел волшебство за этим?

Ну, сначала, когда я увидел вопрос, который был жестким, "это своего рода шутка, потерять кого-то еще", но затем я открыл свою IDE ( "IntelliJ" ), создал класс и пропустил код... и он скомпилирован!!!  Итак, я лучше посмотрел и увидел, что "public static void" был назад, поэтому я пошел туда с помощью курсора и стирал несколько символов.  И что происходит? Шрифты начали стираться назад, поэтому я думал, что mmm.... редко... Я должен выполнить его... Итак, я приступаю к выполнению программы, но сначала мне нужно было сохранить его... и это было , когда я его нашел!. Я не смог сохранить файл, потому что моя IDE заявила, что для некоторых char, существует другая кодировка и укажите, где она была. Поэтому я начинаю исследование в Google по специальным символам, которые могли бы сделать задание и что это:)

Немного о

Двунаправленный алгоритм Unicode и U+202E, кратко объяснить:

Стандарт Unicode предписывает порядок представления памяти, известный как логический порядок. Когда текст представлен в горизонтальных строках, большинство скриптов отображают символы слева направо. Тем не менее, существует несколько сценариев (например, арабский или иврит), где естественный порядок горизонтального текста на дисплее отображается справа налево. Если весь текст имеет равномерное горизонтальное направление, то упорядочение текста дисплея недвусмысленно.

Однако, поскольку эти скрипты справа налево используют цифры, написанные слева направо, текст фактически двунаправлен: смесь текста справа налево и слева направо. В дополнение к цифрам встроенные слова из английского и других сценариев также записываются слева направо, также создавая двунаправленный текст. Без четкой спецификации могут возникать неоднозначности при определении порядка отображения отображаемых символов, когда горизонтальное направление текста неоднородно.

В этом приложении описывается алгоритм, используемый для определения направленности двунаправленного текста Юникода. Алгоритм расширяет неявную модель, используемую в настоящее время рядом существующих реализаций, и добавляет явные символы форматирования для особых обстоятельств. В большинстве случаев нет необходимости включать дополнительную информацию с текстом для получения правильного порядка отображения.

Однако в случае двунаправленного текста существуют обстоятельства, при которых неявное двунаправленное упорядочение недостаточно для создания приемлемого текста. Чтобы справиться с этими случаями, для управления упорядочением символов при визуализации определяется минимальный набор символов направленного форматирования. Это позволяет точно контролировать порядок отображения для разборчивого обмена и гарантирует, что обычный текст, используемый для простых элементов, таких как имена файлов или ярлыки, всегда можно правильно упорядочить для отображения.

Зачем создавать какой-то алгоритм, например this?

алгоритм bidi может отображать последовательность арабского или иврита символы один за другим справа налево.

P.S.: Я знаю, что это не лучший ответ, но было здорово сначала взломать проблему: P

Ответ 4

Глава 3 спецификации языка дает объяснение, подробно описывая, как лексический перевод выполняется для Java-программы. Самое главное для вопроса:

Программы написаны в Юникоде (§ 3.1), но предоставляются лексические переводы (§3.2), так что Unicode escapes (§3.3) может использоваться для включения любого символа Юникода, используя только символы ASCII.

Итак, программа написана в символах Юникода, и автор может избежать их с помощью \uxxxx, если кодировка файла не поддерживает символ Юникода, и в этом случае он переводится на соответствующий символ. Одним из символов Unicode, присутствующим в этом случае, является \u202E. Это не визуально показано в фрагменте, но если вы попытаетесь переключить кодировку браузера, могут появиться скрытые символы.

Следовательно, лексический перевод приводит к объявлению класса:

class M\u202E{

что означает, что идентификатор класса M\u202E. спецификация считает это действительным идентификатором:

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

A "Буква или цифра Java" - это символ, для которого метод Character.isJavaIdentifierPart(int) возвращает true.