270 votes

Pourquoi ce code, écrit à l'envers, affiche-t-il "Hello World!"

Voici un code que j'ai trouvé sur Internet:

class M‮{public static void main(String[]a‭){System.out.print(new char[]
{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}    

Ce code imprime Hello World! sur l'écran; vous pouvez voir courir ici. Je peux voir clairement public static void main écrit, mais il est à l'envers. Comment ce code fonctionne? Comment est-ce même de la compilation?

Edit: j'ai essayé ce code dans l'Ide, et il fonctionne très bien. Cependant, pour une raison quelconque, il ne fonctionne pas dans notepad++, avec cmd. Je n'ai toujours pas trouvé une solution pour que, donc, si quelqu'un ne, un commentaire ci-dessous.

256voto

Davis Broda Points 3680

Il y a des caractères invisibles ici qui modifient la façon dont le code est affiché. Dans l'Ide, ceux-ci peuvent être trouvés par un copier-coller le code dans une chaîne vide (""), qui remplace avec Unicode s'échappe, la suppression de leurs effets et de révéler l'ordre le compilateur voit.

Voici la sortie de ce copier-coller:

"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','!'});}}   "

Le code source caractères sont stockés dans cet ordre, et le compilateur traite comme étant dans cet ordre, mais ils sont affichées de manière différente.

Remarque l' \u202E personnage, qui est un droit-à-gauche pour les remplacer, le démarrage d'un bloc, où tous les personnages sont contraints à être affiché de droite à gauche, et l' \u202D, ce qui est à gauche-à-droite pour les remplacer, à partir d'un bloc imbriqué où tous les personnages sont forcés de gauche à droite, en remplaçant le premier remplacement.

Ergo, lorsqu'il affiche le code d'origine, class M s'affiche normalement, mais l' \u202E renverse l'ordre d'affichage de tout, de là, à l' \u202D, ce qui inverse tout nouveau. (Officiellement, de tout, de la \u202D pour le terminateur de ligne obtient inversé deux fois, une fois en raison de l' \u202D et une fois avec le reste du texte inversé en raison de l' \u202E, ce qui explique pourquoi ce texte s'affiche dans le milieu de la ligne, au lieu de la fin.) La ligne suivante est la directivité est géré de façon indépendante de la première en raison de la terminaison de ligne, de sorte {'H','e','l','l','o',' ','W','o','r','l','d','!'});}} est affiché normalement.

Pour la version intégrale (extrêmement complexe, de plusieurs dizaines de pages) algorithme bidirectionnel Unicode, voir le Standard Unicode Annexe n ° 9.

44voto

James Lawson Points 4734

Il est différent en raison de l' Algorithme Bidirectionnel Unicode. Il y a deux caractères invisibles de BUREAU et LRO que l'Algorithme Bidirectionnel Unicode utilise pour modifier l' apparence visuelle des personnages imbriqués entre ces deux caractères de remplacement.

Le résultat est que visuellement ils regardent dans l'ordre inverse, mais les caractères en mémoire ne sont pas inversés. Vous pouvez analyser les résultats ici. La Java compilateur ignore le BUREAU et LRO, et de les traiter comme des espaces qui est pourquoi le code compile.

Note 1: Cet algorithme est utilisé par les éditeurs de texte et les navigateurs visuellement à l'écran des personnages à la fois LTR caractères (en anglais) et RTL caractères (p. ex. L'arabe, l'hébreu) au même temps - d'où le "bi-directionnelle. Vous pouvez en lire plus à propos de l'Algorithme Bidirectionnel au Unicode du site web.
Note 2: Le comportement de LRO et BUREAU est défini dans la Section 2.2de l'Algorithme.

30voto

Damian Lattenero Points 8950

Le Caractère U+202E miroirs le code de la droite vers la gauche, il est très intelligent mais. Est caché de départ dans le M,

"class M\u202E{..."

Comment ai-je découvert la magie derrière tout cela?

Eh bien, au début quand j'ai vu la question que je durs", c'est une sorte de blague, de perdre quelqu'un d'autre temps", mais ensuite, j'ai ouvert mon IDE ("Ide"), créer une classe, et passé le code... et il a réunies!!! Donc, j'ai pris un meilleur regard et a vu que le "public static void" était en arrière, donc j'y suis allé avec le curseur, et effacer quelques caractères... Et ce qui se passe? Les chars ont commencé effacement arrière, j'ai donc pensé, mmm.... rare... j'ai pour l'exécuter... Donc je procéder pour exécuter le programme, mais j'ai d'abord besoin de l'enregistrer... et c'était quand je l'ai trouvé!. Je ne pouvais pas enregistrer le fichier parce que mon IDE dit qu'il y a un codage différent pour certains char, et de m'indiquer où était-il, Donc, je commence une recherche sur Google pour des caractères spéciaux qui pourraient faire le travail, et c'est tout :)

Un peu plus à propos

l'Algorithme Bidirectionnel Unicode, et U+202E impliqués, brièvement expliquer:

Le Standard Unicode prévoit une mémoire ordonnance de représentation de connu que l'ordre logique. Lorsque le texte est présenté dans les lignes horizontales, la plupart des scripts d'affichage des caractères de gauche à droite. Cependant, il existe plusieurs scripts (comme l'arabe ou l'hébreu), où l'ordre naturel de texte horizontal de l'affichage de droite à gauche. Si tout le texte d'un uniforme de la direction horizontale, puis la commande de l'affichage du texte est sans ambiguïté.

Cependant, parce que ces de droite à gauche scripts utilisent des chiffres qui sont écrits de gauche à droite, le texte bi-directionnel: un mélange de droite à gauche et de gauche à droite. En plus des chiffres, intégré des mots de l'anglais et d'autres langues sont également écrits de gauche à droite, aussi la production de texte bidirectionnel. Sans une spécification claire, des ambiguïtés peuvent survenir dans la détermination de l'ordre des caractères affichés lorsque la direction horizontale du texte n'est pas uniforme.

La présente annexe décrit l'algorithme utilisé pour déterminer la directivité bidirectionnelle de texte Unicode. L'algorithme s'étend le modèle implicite actuellement employé par un certain nombre d'implémentations existantes et ajoute explicite des caractères de formatage pour des circonstances particulières. Dans la plupart des cas, il n'est pas nécessaire d'inclure des informations supplémentaires avec le texte pour obtenir l'affichage correct de la commande.

Toutefois, dans le cas de texte bidirectionnel, il y a des circonstances où un implicite bidirectionnel de la commande n'est pas suffisante pour produire compréhensibles. Pour traiter ces cas, un ensemble minimal de formatage directionnel caractères est définie à la commande de caractères lors du rendu. Cela permet un contrôle précis de l'écran de commande pour lisible échange et s'assure que le texte brut utilisé pour les produits simples comme les noms de fichiers ou des étiquettes peuvent toujours être correctement ordonné pour l'affichage.

Pourquoi créer un algorithme comme cela?

l'algorithme bidi pouvez effectuer le rendu d'une séquence de l'arabe ou de l'hébreu les caractères les uns après les autres de droite à gauche.

P. S.: je sais que c'est pas la meilleure solution, mais c'était amusant à craquer d'abord le problème :P

5voto

manouti Points 10398

Le chapitre 3 de la spécification du langage fournit une explication en décrivant en détail la façon dont le lexique de traduction est effectuée par un programme Java. Ce qui importe le plus pour la question:

Les programmes sont écrits en Unicode (§3.1), mais lexicale traductions sont fournies (§3.2), de sorte que Unicode s'en échappe (§3.3) peut être utilisé pour inclure tout caractère Unicode en utilisant uniquement des caractères ASCII.

Si un programme est écrit en caractères Unicode, et l'auteur peut échapper à l'aide de \uxxxx dans le cas où le codage de fichier ne prend pas en charge les caractères Unicode, auquel cas il est traduit pour le caractère approprié. L'un des caractères Unicode présent dans ce cas, est - \u202E. Il n'est pas visuellement le montre l'extrait, mais si vous essayez de changer l'encodage du navigateur, les personnages cachés peuvent apparaître.

Par conséquent, le lexique de la traduction dans la déclaration de classe:

class M\u202E{

ce qui signifie que l'identificateur de classe est - M\u202E. La spécification de la considère comme valide identifiant:

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

Un "Java lettres ou des chiffres" est un personnage pour qui la méthode Character.isJavaIdentifierPart(int) renvoie la valeur true.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X