当一位同事向我展示这一行JavaScript警报42时,我感到困惑。
alert(2+ 40);
很快就发现,看起来像减号的实际上是具有明显不同语义的奥秘Unicode字符。
这让我想知道为什么在解析表达式时该字符不会产生语法错误。我还想知道是否还有更多这样的字符。
;
,编辑器倾向于将奇怪的``字符更改为普通空间,但是如果撤消该“自动更正”,则具有相同的行为。 。即使看起来像连字符或减号(使用常规字体),该字符也具有与空格相同的语义。
当一位同事向我展示这一行JavaScript警报42时,我感到困惑。
alert(2+ 40);
很快就发现,看起来像减号的实际上是具有明显不同语义的奥秘Unicode字符。
这让我想知道为什么在解析表达式时该字符不会产生语法错误。我还想知道是否还有更多这样的字符。
;
,编辑器倾向于将奇怪的``字符更改为普通空间,但是如果撤消该“自动更正”,则具有相同的行为。 。即使看起来像连字符或减号(使用常规字体),该字符也具有与空格相同的语义。
Answers:
该字符是“ OGHAM SPACE MARK”,这是一个空格字符。因此,代码等同于alert(2+ 40)
。
我还想知道是否还有更多这样的字符。
Zs类中的任何Unicode字符在JavaScript中都是空格字符,但似乎没有那么多。
但是,JavaScript还允许标识符中使用Unicode字符,这使您可以使用有趣的变量名,例如ಠ_ಠ
。
Zs
JavaScript中不仅将字符视为空格。还有更多:github.com/mathiasbynens/regexpu/blob/...
ಠ_ಠ
,可以使用如在JS的标识符:ಠ_ಠ
ಠ
被视为字母只是常识,因为它是字母。如果ಠ_ಠ
不能用作标识符,那将是一个明显的错误。
阅读完其他答案后,我写了一个简单的脚本来查找U + 0000–U + FFFF范围内的所有Unicode字符,它们的行为类似于空格。看起来,取决于浏览器,其中有26或27个,但对U + 0085和U + FFFE的意见不同。
请注意,大多数这些字符看起来就像是常规空格。
\p{Default Ignorable Code Point}
,而不仅仅是一个\p{Noncharacter Code Pount}
。U + 0085一直是\p{Whitespace}
代码点。邪恶的是U + 180E蒙古腔分隔器,“最近”失去了它的\p{Whitespace}
财产。请注意,这\p{Pattern Whitespace}
是一个更小的集合,并且是不可变的属性。但是\p{Whitespace}
不是。
FEFF
是BOM,可以将其视为文本中的“零宽度不间断空格”。FFFE
它是字节序互换的。也许这就是某些浏览器将其视为空白的原因。
看来您正在使用的字符实际上比实际的负号(连字符)更长。
-
顶部是您正在使用的内容,底部是负号应该是什么。您似乎确实已经知道这一点,所以现在让我们看看为什么Javascript会这样做。
您使用的字符实际上是ogham空格标记,它是一个空格字符,因此它基本上被解释为与空格相同,这意味着您的语句类似于alert(2+ 40)
Javascript。
Javascript中还有其他类似的字符。您可以在Wikipedia上查看完整列表。
我注意到该字符的有趣之处在于Google Chrome(和其他可能的浏览器)在页面顶部栏中解释该字符的方式。
这是一个1680
内部的块。这实际上是ogham空格标记的unicode号。看来这只是我的机器在做,但是这很奇怪。
我决定用其他语言尝试一下,看看会发生什么,这些就是我得到的结果。
Python 2和3
>> 2+ 40
File "<stdin>", line 1
2+ 40
^
SyntaxError: invalid character in identifier
红宝石
>> 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(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
走
>> 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.
方案
>> (+ 2 40)
=> 42
C#
(Main()
方法内)
Console.WriteLine(2+ 40);
Output: 42
Perl 6
>> ./perl6 -e'say 2+ 40'
42
sudo apt-get install unicode
,尽管只是经过数小时的研究和失败的尝试)
我想它必须与以下事实有关:由于某种奇怪的原因,它归类为空格:
$ 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)
unicode
。
' '.codePointAt(0)
控制台上的@PSkocik 将产生5760。现在是Google 5760 unicode。
我还想知道是否还有更多这样的字符。
我似乎记得有一段时间读过一篇文章,内容是用希腊问号U + 037E巧妙地替换了某人代码中的分号(U + 003B)。
它们看上去都一样(就我所相信的希腊人而言,他们使用的是U + 003B),但本文指出,另一种则行不通。
来自Wikipedia的一些更多信息在这里: https //en.wikipedia.org/wiki/Question_mark#Greek_question_mark
关于将其用作SO本身的恶作剧的一个(封闭的)问题。虽然不是我最初阅读的地方: JavaScript恶作剧/开玩笑