【问题标题】:Why does 2+ 40 equal 42?为什么 2+ 40 等于 42?
【发布时间】:2015-10-09 00:33:57
【问题描述】:

当一位同事向我展示这行 JavaScript 警报 42 时,我感到很困惑。

alert(2+ 40);

很快发现,看起来像减号的东西实际上是一个语义明显不同的神秘 Unicode 字符。

这让我想知道为什么在解析表达式时该字符不会产生语法错误。我也想知道是否还有更多这样的角色。

【问题讨论】:

  • @Elyasin 你是复制/粘贴还是重新输入?
  • 这也适用于 Visual C#。将奇怪的字符粘贴到 Visual Studio IDE 中时,或通过键入 ; 完成语句时,编辑器倾向于将奇怪的 ` ` 字符更改为正常空格,但如果撤消该“自动更正”,则相同的行为。该字符与空格具有相同的语义,即使它看起来像连字符或减号(在通常的字体中)。
  • 相反的情况也可能发生。一些在标识符中支持 unicode 的语言接受看起来像空格的 unicode 字符(换句话说,你看不到它们);甚至可能有完全不可见的标识符。
  • (OT) 因为 42 是一切的答案?
  • @Thomas 意外结果是由那个 Unicode 字符引起的这一事实已经很清楚了。

标签: javascript unicode


【解决方案1】:

那个字符是"OGHAM SPACE MARK",它是一个空格字符。所以代码相当于alert(2+ 40)

我也想知道是否还有更多这样的角色。

Zs 类 is a white space character in JavaScriptbut there don't seem to be that many 中的任何 Unicode 字符。

但是,JavaScript also allows Unicode characters in identifiers,它允许您使用有趣的变量名称,例如 ಠ_ಠ

【讨论】:

  • Box-with-a-hex-code 下划线 box-with-a-hex-code。它应该是哪个角色?
  • @immibis 这个答案的最后一部分是disapprovallook.com@immibis 以图像形式提供的表情符号
  • 请注意,在 JavaScript 中不仅仅是Zs 字符被认为是空白。还有更多:github.com/mathiasbynens/regexpu/blob/…
  • ಠ_ಠ可以在JS中用作标识符时我的反应:ಠ_ಠ
  • @ChrisCirefice 下划线被视为字母在 C 风格语言中由来已久。 被视为字母只是常识,因为它是字母。如果ಠ_ಠ 不能用作标识符,那将是一个明显的错误。
【解决方案2】:

阅读其他答案后,我编写了一个简单的脚本来查找 U+0000–U+FFFF 范围内的所有 Unicode 字符,这些字符的行为类似于空格。看起来有 26 或 27 个,具体取决于浏览器,对于 U+0085 和 U+FFFE 存在分歧。

请注意,这些字符中的大多数看起来就像一个普通的空格。

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; }

【讨论】:

  • U+0085 "NEL" 被 Unicode 定义为空白,但长期以来一直被错误处理。 U+FFFE 是一个非字符,除了 NChar 之外没有名称和属性,不应被任何合理的视为空白。也就是说,我的浏览器在这两点上都不同意我的观点:)
  • @hobbs 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 是等效的字节序交换。也许这就是某些浏览器将其视为空格的原因。
  • ecma-international.org/ecma-262/6.0/#sec-white-space (链接自 Felix King 的回答)特别指出 U+FEFF 被视为 JS 源代码中的空白。 U+FFFE 没有列出,但我觉得这是一个遗漏错误。
  • @zwol,不是遗漏错误,因为没有字符U+FFFE。将其视为空白是​​一个错误。事实上,在大多数情况下,将其视为有效字符是一个错误。根据 JS 规范,U+0085 不是空格,但是该规范要求 U+0085 的特殊大小写不是新行,这很奇怪,可以说是规范中的一个错误。
【解决方案3】:

您使用的字符似乎比实际的减号(连字符)长。

 
-

顶部是你正在使用的,底部是减号应该是什么。你似乎已经知道了,所以现在让我们看看为什么 Javascript 会这样做。

您使用的字符实际上是ogham space mark,它是一个空白字符,因此它基本上被解释为与空格相同的东西,这意味着您的语句在Javascript中看起来像alert(2+ 40)

在 Javascript 中还有其他类似的字符。您可以查看完整列表here on Wikipedia


我注意到这个字符的一个有趣的地方是谷歌浏览器(以及可能的其他浏览器)在页面顶部栏中解释它的方式。

这是一个块,里面有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

【讨论】:

  • Ubuntu 不是问题。您使用的窗口标题字体是。
  • firefox (iceweasel) 和 debian 上的 google chrome 似乎可以很好地显示 unicode 字符,尽管我已经竭尽全力确保我的系统上的 unicode 兼容性。 (实际上,我做的最有用的事情是最简单的:sudo apt-get install unicode,虽然只是经过数小时的研究和失败的尝试)
  • @PSkocik 有趣的是,我以前在这里遇到过字体问题,所以很可能
  • @PSkocik “Ubuntu 不是问题。您正在使用的窗口标题字体是。” …即“Ubuntu”。
  • @PSkocik 我终于修好了 :) 只需要更改系统标题栏字体。
【解决方案4】:

我想这与出于某种奇怪的原因将其归类为空白有关:

$ 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)

【讨论】:

  • 如果这是从您的终端复制和粘贴的,我想知道您在哪里找到了命令 unicode
  • 它来自 Radovan Garabík 名为(等待它...)unicode 的 Ubuntu 软件包。对应的仓库在github.com/garabik/unicode
  • 好的,感谢 github 链接。 AFAICT,它不在 Fedora 存储库中。
  • @PSkocik ' '.codePointAt(0) 在控制台将产生 5760。现在 google 5760 unicode。
【解决方案5】:

我也想知道是否还有更多这样的角色。

我似乎记得不久前读过一篇文章,内容是用希腊问号 U+037E 恶作剧地替换某人代码中的分号 (U+003B)。

它们看起来都一样(在某种程度上我相信希腊人自己使用 U+003B)但是这篇文章指出另一个不起作用。

更多来自维基百科的信息在这里:https://en.wikipedia.org/wiki/Question_mark#Greek_question_mark

还有一个(封闭的)问题,关于将其用作 SO 本身的恶作剧。不是我最初在AFAIR读到的地方: JavaScript Prank / Joke

【讨论】:

    【解决方案6】:

    许多语言不会编译这个表达式,但我很好奇 Rust 的编译器在这个话题上是怎么说的。它是出了名的严格,但往往会给我们以慈爱的知识和智慧。

    所以我要求它编译这个:

    fn main() {
        println!("{}", (2+ 40));
    }
    

    编译器回复:

    error: unknown start of token: \u{1680}
      |
      |     println!("{}", (2+ 40));
      |                       ^
      |
    help: Unicode character ' ' (Ogham Space mark) looks like ' ' (Space), but it is not
    

    另一方面,JavaScript(用当今最新和最常用的浏览器测试)似乎对这个字符很冷淡,只是忽略了它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-04-12
      • 2014-07-04
      • 2017-11-06
      • 2021-03-10
      • 2013-08-17
      • 2021-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多