Dlaczego 2+ 40 równa się 42?
Byłem zdumiony, gdy kolega pokazał mi tę linię alarmowania JavaScript 42.
alert(2+ 40);
Szybko okazuje się, że to, co wygląda jak znak minus, jest tajemnym znakiem Unicode o wyraźnie odmiennej semantyce.
To sprawiło, że zastanawiałem się, dlaczego ten znak nie generuje błędu składni podczas parsowania wyrażenia. Chciałbym też wiedzieć, czy jest więcej postaci zachowujących się w ten sposób.
5 answers
Ten znak to "znak przestrzeni OGHAM" , który jest znakiem spacji. Więc kod jest odpowiednikiem alert(2+ 40)
.
Chciałbym też wiedzieć, czy jest więcej postaci zachowujących się w ten sposób.
Dowolny znak Unicode w klasie ZS jest białym znakiem spacji w JavaScript, ale nie wydaje się być tak wiele.
Jednak JavaScript pozwala również na użycie znaków Unicode w identyfikatorach , co pozwala na użycie interesującej zmiennej nazwy typu ಠ_ಠ
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-26 00:26:56
Po przeczytaniu pozostałych odpowiedzi napisałem prosty skrypt, aby znaleźć wszystkie znaki Unicode w zakresie U + 0000-u + FFFF, które zachowują się jak białe spacje. Jak się wydaje, jest ich 26 lub 27 w zależności od przeglądarki, z nieporozumieniami na temat U + 0085 i U + FFFE.
Zauważ, że większość z tych znaków wygląda jak zwykła biała spacja.
function isSpace(ch)
{
try
{
return Function('return 2 +' + ch + ' 2')() === 4;
}
catch(e)
{
return false;
}
}
for (var i = 0; i <= 0xffff; ++i)
{
var ch = String.fromCharCode(i);
if (isSpace(ch))
{
document.body.appendChild(document.createElement('DIV')).textContent = 'U+' + ('000' + i.toString(16).toUpperCase()).slice(-4) + ' "' + ch + '"';
}
}
div { font-family: monospace; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-20 13:33:47
Wygląda na to, że znak, którego używasz, jest dłuższy niż rzeczywisty znak minus (myślnik).
-
Góra jest tym, czego używasz, dół jest tym, co powinien być znak minus. Wydaje się, że już to wiesz, więc teraz zobaczmy, dlaczego Javascript to robi.
Znak, którego używasz, jest w rzeczywistości znacznikiem przestrzeni ogham, który jest białym znakiem spacji, więc jest zasadniczo interpretowany jako to samo, co spacja, co oznacza, że Twoje instrukcja wygląda jak alert(2+ 40)
do Javascript.
Istnieją inne znaki tego typu w Javascript. Możesz zobaczyć pełną listę tutaj na Wikipedii .
Coś ciekawego zauważyłem w tej postaci jest sposób, w jaki Google Chrome (i Możliwe inne przeglądarki) interpretuje go w górnym pasku strony.
Jest to blok z 1680
wewnątrz niego. W rzeczywistości jest to numer unicode dla znaku przestrzeni ogham. Wygląda na to, że to tylko moje maszyna robi to, ale to dziwna rzecz.
Postanowiłem wypróbować to w innych językach, aby zobaczyć, co się stanie i oto wyniki, które otrzymałem.
Języki, w których nie działa:
Python 2 & 3
>> 2+ 40
File "<stdin>", line 1
2+ 40
^
SyntaxError: invalid character in identifier
Ruby
>> 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 (wewnątrz metody main
)
>> 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
Idź
>> 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.
Języki, w których działa:
Schemat
>> (+ 2 40)
=> 42
C #
(wewnątrz metody Main()
)
Console.WriteLine(2+ 40);
Output: 42
Perl 6
>> ./perl6 -e'say 2+ 40'
42
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
Myślę, że to ma coś wspólnego z faktem, że z jakiegoś dziwnego powodu klasyfikuje się jako białe spacje:
$ unicode
U+1680 OGHAM SPACE MARK
UTF-8: e1 9a 80 UTF-16BE: 1680 Decimal:  
( )
Uppercase: U+1680
Category: Zs (Separator, Space)
Bidi: WS (Whitespace)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-19 23:57:18
Chciałbym też wiedzieć, czy jest więcej postaci zachowujących się w ten sposób.
Wydaje mi się, że jakiś czas temu czytałem artykuł o złośliwym zastępowaniu półkolonów (U+003B) w czyimś kodzie przez U+037E, który jest greckim znakiem zapytania.
Oba wyglądają tak samo (do tego stopnia, że wierzę, że Grecy sami używają U + 003B), ale ten artykuł stwierdził, że drugi nie zadziała.
Więcej informacji na ten temat z Wikipedii znajduje się tutaj: https://en.wikipedia.org/wiki/Question_mark#Greek_question_mark
I (zamknięte) pytanie o wykorzystanie tego jako żart z samego SO. Nie tam, gdzie pierwotnie czytałem to AFAIR chociaż: JavaScript Prank / Joke
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:08