Aqui está um código que eu encontrei na Internet:
class M{public static void main(String[]a){System.out.print(new char[]
{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}
Esse código é impresso Hello World!
na tela; você pode vê-lo aqui . Eu posso ver claramente public static void main
escrito, mas é ao contrário. Como esse código funciona? Como isso compila?
Edit: Eu tentei esse código no IntellIJ, e funciona bem. No entanto, por algum motivo, ele não funciona no bloco de notas ++, junto com o cmd. Ainda não encontrei uma solução para isso, então, se alguém encontrar, comente abaixo.
java
unicode
right-to-left
Abóbora imaginária
fonte
fonte
M
e também depois[]a
: fileformat.info/info/unicode/char/202d/index.htm É chamado OVERRIDE da esquerda para a direitaniam diov citats cilbup
Soa como um provérbio latino ..Respostas:
Existem caracteres invisíveis aqui que alteram a forma como o código é exibido. No Intellij, eles podem ser encontrados copiando e colando o código em uma string vazia (
""
), que os substitui por escapes Unicode, removendo seus efeitos e revelando a ordem que o compilador vê.Aqui está a saída dessa copiar e colar:
Os caracteres do código-fonte são armazenados nesta ordem e o compilador os trata como estando nessa ordem, mas são exibidos de maneira diferente.
Observe o
\u202E
caractere, que é uma substituição da direita para a esquerda, iniciando um bloco em que todos os caracteres são forçados a serem exibidos da direita para a esquerda e o\u202D
, que é uma substituição da esquerda para a direita, iniciando um bloco aninhado onde todos os caracteres são forçados na ordem da esquerda para a direita, substituindo a primeira substituição.Logo, quando ele exibe o código original,
class M
é exibido normalmente, mas\u202E
inverte a ordem de exibição de tudo, de lá para o\u202D
, o que reverte tudo novamente. (Formalmente, tudo, desde o terminal\u202D
até a linha, é revertido duas vezes, uma vez devido ao\u202D
e uma vez com o restante do texto revertido devido ao\u202E
, motivo pelo qual esse texto aparece no meio da linha e não no final.) A direcionalidade da próxima linha é tratada independentemente da primeira devido ao terminador da linha,{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}
sendo exibida normalmente.Para o algoritmo bidirecional Unicode completo (extremamente complexo, com dezenas de páginas), consulte o Anexo # 9 do Padrão Unicode .
fonte
Parece diferente devido ao algoritmo bidirecional Unicode . Existem dois caracteres invisíveis de RLO e LRO que o Algoritmo Bidirecional Unicode usa para alterar a aparência visual dos caracteres aninhados entre esses dois metacaracteres.
O resultado é que visualmente eles olham em ordem inversa, mas os caracteres reais na memória não são revertidos. Você pode analisar os resultados aqui . O compilador Java ignorará o RLO e o LRO e os tratará como espaço em branco, e é por isso que o código é compilado.
Nota 1: esse algoritmo é usado pelos editores de texto e navegadores para exibir visualmente os caracteres LTR (inglês) e RTL (por exemplo, árabe, hebraico) juntos ao mesmo tempo - portanto, bidirecional. Você pode ler mais sobre o algoritmo bidirecional no site da Unicode .
Nota 2: O comportamento exato de LRO e RLO é definido na Seção 2.2 do algoritmo.
fonte
M\u202E
ea\u202D
, mas os identificadores parecem estar equiparados aM
ea
. (O JLS não explica muito bem isso.) #O personagem
U+202E
reflete o código da direita para a esquerda, mas é muito inteligente. Está oculto começando no M,Bem, no começo, quando vi a pergunta difícil, "é uma piada, perder o tempo de outra pessoa", mas depois abri meu IDE ("IntelliJ"), criei uma classe e passei o código ... e compilou !!! Então, olhei melhor e vi que o "vazio público estático" estava para trás, então fui lá com o cursor e apaguei alguns caracteres ... E o que acontece? Os caracteres começaram a apagar para trás , então, pensei mmm .... raro ... tenho que executá-lo ... Então, continuo executando o programa, mas primeiro eu preciso salvá-lo ... e foi aí que eu encontrei! . Não pude salvar o arquivo porque meu IDE disse que havia uma codificação diferente para algum caractere e me indicou onde estava., Então inicio uma pesquisa no Google para caracteres especiais que podem fazer o trabalho, e é isso :)
o algoritmo bidirecional Unicode e
U+202E
envolvido, explique brevemente :Por que criar um algoritmo como este ?
fonte
O Capítulo 3 da especificação de linguagem fornece uma explicação, descrevendo em detalhes como a tradução lexical é feita para um programa Java. O que é mais importante para a pergunta:
Portanto, um programa é escrito em caracteres Unicode, e o autor pode escapá-los usando
\uxxxx
no caso de a codificação do arquivo não suportar o caractere Unicode, caso em que é traduzido para o caractere apropriado. Um dos caracteres Unicode presentes neste caso é\u202E
. Não é mostrado visualmente no trecho, mas se você tentar alternar a codificação do navegador, os caracteres ocultos poderão aparecer.Portanto, a tradução lexical resulta na declaração de classe:
o que significa que o identificador de classe é
M\u202E
. A especificação considera isso como um identificador válido:fonte