Warum ist 2+ 40 gleich 42?

360

Ich war verblüfft, als mir ein Kollege diese Zeile der JavaScript-Warnung 42 zeigte.

alert(2+ 40);

Es stellt sich schnell heraus, dass das, was wie ein Minuszeichen aussieht, tatsächlich ein arkanes Unicode-Zeichen mit deutlich unterschiedlicher Semantik ist.

Daher habe ich mich gefragt, warum dieses Zeichen beim Analysieren des Ausdrucks keinen Syntaxfehler erzeugt. Ich würde auch gerne wissen, ob sich mehr Charaktere so verhalten.

GOTO 0
quelle
28
@Elyasin Haben Sie kopiert / eingefügt oder erneut eingegeben?
user253751
4
Dies funktioniert auch in Visual C #. Wenn Sie das seltsame Zeichen in die Visual Studio-IDE einfügen oder die Anweisung durch Eingabe vervollständigen ;, ändert der Editor das seltsame `` Zeichen in einen normalen Bereich. Wenn Sie diese "Autokorrektur" jedoch rückgängig machen, haben Sie dasselbe Verhalten . Dieses Zeichen hat dieselbe Semantik wie ein Leerzeichen, auch wenn es wie ein Bindestrich oder ein Minus aussieht (in üblichen Schriftarten).
Jeppe Stig Nielsen
4
Das Gegenteil kann auch passieren. Einige Sprachen, die Unicode in Bezeichnern unterstützen, akzeptieren Unicode-Zeichen, die wie Leerzeichen aussehen (mit anderen Worten, Sie können sie nicht sehen). Es kann sogar möglich sein, vollständig unsichtbare Kennungen zu haben.
Gnasher729
58
(OT) Weil 42 eine Antwort auf alles ist?
ivan_pozdeev
4
@Thomas die Tatsache, dass das unerwartete Ergebnis durch dieses Unicode-Zeichen verursacht wurde, war bereits klar.
GOTO 0

Antworten:

470

Dieses Zeichen ist "OGHAM SPACE MARK" , ein Leerzeichen. Der Code entspricht also alert(2+ 40).

Ich würde auch gerne wissen, ob es mehr Charaktere gibt, die sich so verhalten.

Jedes Unicode-Zeichen in der Zs-Klasse ist ein Leerzeichen in JavaScript , aber es scheint nicht so viele zu geben .

Allerdings erlaubt JavaScript auch Unicode - Zeichen in Bezeichnern , die Sie wie verwenden interessante Variablennamen können ಠ_ಠ.

Felix Kling
quelle
3
Box-mit-einem-Hex-Code unterstreicht Box-mit-einem-Hex-Code. Welcher Charakter soll es sein?
user253751
12
@immibis Der letzte Teil dieser Antwort ein Emoticon in Bildform finden Sie unter disapprovallook.com
Mark S.
3
Beachten Sie, dass Zsin JavaScript nicht nur Zeichen als Leerzeichen betrachtet werden. Es gibt mehr: github.com/mathiasbynens/regexpu/blob/…
Mathias Bynens
20
Meine Reaktion, wann ಠ_ಠals Kennung in JS verwendet werden kann: ಠ_ಠ
Chris Cirefice
2
Der @ ChrisCirefice-Unterstrich, der als Buchstabe behandelt wird, hat in C-Sprachen eine lange Tradition. als Brief behandelt zu werden ist nur gesunder Menschenverstand, da es ein Brief ist. Es wäre ein klarer Fehler, wenn er ಠ_ಠnicht als Kennung verwendet werden könnte.
Jon Hanna
81

Nachdem ich die anderen Antworten gelesen hatte, schrieb ich ein einfaches Skript, um alle Unicode-Zeichen im Bereich U + 0000 - U + FFFF zu finden, die sich wie Leerzeichen verhalten. Wie es scheint, gibt es je nach Browser 26 oder 27 davon, mit Meinungsverschiedenheiten über U + 0085 und U + FFFE.

Beachten Sie, dass die meisten dieser Zeichen nur wie ein normaler Leerraum aussehen.

GOTO 0
quelle
17
U + 0085 "NEL" wird von Unicode als Leerzeichen definiert, hat aber eine lange Geschichte der Misshandlung. U + FFFE ist ein Nicht-Zeichen ohne Namen und ohne Eigenschaften außer NChar und sollte von nichts Vernünftigem als Leerzeichen betrachtet werden. Das heißt, mein Browser ist in beiden Punkten nicht mit mir einverstanden :)
Hobbs
4
@hobbs U + FFFE ist auch ein \p{Default Ignorable Code Point}, nicht nur ein \p{Noncharacter Code Pount}. U + 0085 war schon immer ein \p{Whitespace}Codepunkt. Der Böse ist der MONGOLISCHE Vokaltrenner U + 180E, der „vor kurzem“ sein \p{Whitespace}Eigentum verloren hat . Beachten Sie, dass dies \p{Pattern Whitespace}eine viel kleinere Menge und eine unveränderliche Eigenschaft ist. Ist \p{Whitespace}aber nicht.
Tchrist
2
FEFFist die Stückliste und kann in Texten wie ein "No-Break-Leerzeichen mit der Breite Null" behandelt werden. FFFEist es Endian getauscht Äquivalent. Vielleicht ist das der Grund, warum manche Browser Whitespace behandeln.
CodesInChaos
ecma-international.org/ecma-262/6.0/#sec-white-space (wie aus Felix Kings Antwort verknüpft) ruft U + FEFF ausdrücklich als Leerzeichen im JS-Quellcode auf. U + FFFE ist nicht aufgeführt, aber das erscheint mir als Auslassungsfehler.
zwol
1
@zwol, es ist kein Auslassungsfehler, da es kein Zeichen U + FFFE gibt. Es als Leerzeichen zu behandeln, ist ein Fehler. In der Tat ist es in den meisten Fällen ein Fehler, es überhaupt als gültigen Charakter zu behandeln. U + 0085 ist nach JS-Spektren kein Leerraum, aber diese Spezifikation, die ein spezielles Gehäuse von U + 0085 erfordert, um keine neue Linie zu sein, ist bizarr und wahrscheinlich ein Fehler in der Spezifikation.
Jon Hanna
56

Es scheint, dass das von Ihnen verwendete Zeichen tatsächlich länger ist als das tatsächliche Minuszeichen (ein Bindestrich).

 
-

Oben ist das, was Sie verwenden, unten ist das Minuszeichen. Sie scheinen das bereits zu wissen. Lassen Sie uns nun sehen, warum Javascript dies tut.

Das Zeichen, das Sie verwenden, ist eigentlich das ogham-Leerzeichen, bei dem es sich um ein Leerzeichen handelt. Daher wird es im Grunde genommen als dasselbe wie ein Leerzeichen interpretiert, was bedeutet, dass Ihre Aussage alert(2+ 40)für Javascript aussieht .

Es gibt andere Zeichen wie dieses in Javascript. Eine vollständige Liste finden Sie hier auf Wikipedia .


Interessant an diesem Charakter ist die Art und Weise, wie Google Chrome (und möglicherweise andere Browser) ihn in der oberen Leiste der Seite interpretiert.

Geben Sie hier die Bildbeschreibung ein

Es ist ein Block mit 1680innen. Das ist eigentlich die Unicode-Nummer für die Ogham-Leerzeichen. Es scheint nur meine Maschine zu sein, die das tut, aber es ist eine seltsame Sache.


Ich habe beschlossen, dies in anderen Sprachen auszuprobieren, um zu sehen, was passiert, und dies sind die Ergebnisse, die ich erhalten habe.


Sprachen, in denen es nicht funktioniert:

Python 2 & 3

>> 2+ 40
  File "<stdin>", line 1
    2+ 40
        ^
SyntaxError: invalid character in identifier

Rubin

>> 2+ 40
NameError: undefined local variable or method ` 40' for main:Object
    from (irb):1
    from /home/michaelpri/.rbenv/versions/2.2.2/bin/irb:11:in `<main>'

Java (innerhalb der mainMethode)

>> System.out.println(2+ 40);
Main.java:3: error: illegal character: \5760
            System.out.println(2+?40);
                                 ^
Main.java:3: error: ';' expected
            System.out.println(2+?40);
                                  ^
Main.java:3: error: illegal start of expression
            System.out.println(2+?40);
                                    ^
3 errors

PHP

>> 2+ 40;
Use of undefined constant  40 - assumed ' 40' :1

C.

>> 2+ 40
main.c:1:1: error: expected identifier or '(' before numeric constant
 2+ 40
 ^
main.c:1:1: error: stray '\341' in program
main.c:1:1: error: stray '\232' in program
main.c:1:1: error: stray '\200' in program

exit status 1

Gehen

>> 2+ 40
can't load package: package .: 
main.go:1:1: expected 'package', found 'INT' 2
main.go:1:3: illegal character U+1680

exit status 1

Perl 5

>> perl -e'2+ 40'                                                                                                                                   
Unrecognized character \xE1; marked by <-- HERE after 2+<-- HERE near column 3 at -e line 1.

Sprachen, in denen es funktioniert:

Planen

>> (+ 240)
=> 42

C # (innerhalb der Main()Methode)

Console.WriteLine(2+ 40);

Output: 42

Perl 6

>> ./perl6 -e'say 2+ 40' 
42
michaelpri
quelle
34
Ubuntu ist nicht das Problem. Die von Ihnen verwendete Fenstertitelschrift ist.
PSkocik
2
Firefox (iceweasel) und Google Chrome auf Debian scheinen das Unicode-Zeichen gut anzuzeigen, obwohl ich mich sehr bemüht habe, die Unicode-Kompatibilität auf meinem System sicherzustellen. (Eigentlich war das Nützlichste, was ich getan habe, das Einfachste: sudo apt-get install unicodeobwohl erst nach stundenlangen Nachforschungen und fehlgeschlagenen Versuchen)
sig_seg_v
@PSkocik Interessant, ich hatte hier schon einmal Probleme mit der Schrift, also ist das wahrscheinlich
Michaelpri
51
@PSkocik „Ubuntu ist nicht das Problem. Die von Ihnen verwendete Fenstertitelschrift ist. " … Das ist „ Ubuntu “.
user4642212
1
@PSkocik Ich habe es endlich behoben :) Muss nur die Schriftart der Systemtitelleiste ändern.
Michaelpri
43

Ich denke, es hat etwas damit zu tun, dass es aus irgendeinem seltsamen Grund als Leerzeichen klassifiziert wird:

$ unicode  
U+1680 OGHAM SPACE MARK
UTF-8: e1 9a 80  UTF-16BE: 1680  Decimal: &#5760;( )
Uppercase: U+1680
Category: Zs (Separator, Space)
Bidi: WS (Whitespace)
PSkocik
quelle
Wenn dies ein Kopieren und Einfügen von Ihrem Terminal ist, möchte ich wissen, wo Sie den Befehl gefunden haben unicode.
BenjiWiebe
16
Es ist aus dem Ubuntu-Paket unicodevon Radovan Garabík (warte darauf ...) . Das entsprechende Repo finden Sie unter github.com/garabik/unicode .
PSkocik
OK, danke für den Github-Link. AFAICT, es ist nicht in den Fedora-Repos.
BenjiWiebe
@PSkocik ' '.codePointAt(0)an der Konsole ergibt 5760. Jetzt google 5760 Unicode.
Royi Namir
6

Ich würde auch gerne wissen, ob es mehr Charaktere gibt, die sich so verhalten.

Ich erinnere mich an ein Stück, in dem es vor einiger Zeit darum ging, Semikolons (U + 003B) in einem Code durch U + 037E, das griechische Fragezeichen, zu ersetzen.

Sie sehen beide gleich aus (soweit ich glaube, dass die Griechen selbst U + 003B verwenden), aber in diesem Artikel heißt es, dass der andere nicht funktionieren würde.

Weitere Informationen hierzu aus Wikipedia finden Sie hier: https://en.wikipedia.org/wiki/Question_mark#Greek_question_mark

Und eine (geschlossene) Frage, wie man dies als Streich von SO selbst benutzt. Nicht dort, wo ich es ursprünglich AFAIR gelesen habe: JavaScript Prank / Joke

Mittag und
quelle