なぜ2 + 40は42に等しいのですか?


360

同僚がこのJavaScriptの警告42の行を見せてくれたとき、私は困惑しました。

alert(2+ 40);

マイナス記号のように見えるのは、実際にはセマンティクスが明らかに異なる難解なUnicode文字であることがすぐにわかります。

これにより、式の解析時にその文字が構文エラーを生成しないのはなぜかと疑問に思いました。このように振る舞うキャラクターが他にもいるかどうかも知りたいです。


28
@Elyasinコピー/貼り付けまたは再入力しましたか?
user253751 2015

4
これはVisual C#でも機能します。奇妙な文字をVisual Studio IDEに貼り付けるとき、またはを入力してステートメントを完了するとき;、エディターは奇妙な ``文字を通常のスペースに変更する傾向がありますが、その「自動修正」を元に戻すと、同じ動作になります。その文字は、(通常のフォントでは)ハイフンまたはマイナスのように見えても、スペースと同じセマンティクスを持っています。
Jeppe Stig Nielsen、

4
逆も起こり得ます。識別子でUnicodeをサポートする言語の中には、空白のように見える(つまり、見えない)Unicode文字を受け入れるものがあります。完全に見えない識別子を持つことさえ可能かもしれません。
gnasher729 2015

58
(OT)42はすべて
ivan_pozdeev 2015

4
@Thomas予期しない結果がそのUnicode文字によって引き起こされたという事実はすでに明らかでした。
GOTO 0

回答:


470

あのキャラクターは、スペースキャラクター「OGHAM SPACE MARK」です。したがって、コードはと同等alert(2+ 40)です。

このように振る舞うキャラクターが他にもいるかどうかも知りたいです。

ZsクラスのUnicode文字はJavaScriptでは空白文字ですが、それほど多くはないようです

ただし、JavaScriptでは識別子Unicode文字も使用できるため、などの興味深い変数名を使用できますಠ_ಠ


3
16進コードのボックスの下線16進コードのボックスの下線。どんなキャラクターなの?
user253751 2015

12
@immibisこの回答の最後の部分は、disapprovallook.com
Mark S.

3
ZsJavaScriptでは文字だけが空白と見なされるわけではないことに注意してください。もっとありますgithub.com/mathiasbynens/regexpu/blob/...
マティアスBynens

20
私の反応ಠ_ಠJSで識別子として使用することができます。ಠ_ಠ
クリスCirefice

2
@ChrisCireficeが文字として扱われることを強調するのは、Cスタイルの言語では長年のことです。手紙なので、手紙として扱われるのは常識です。ಠ_ಠ識別子として使用できなければ、それは明らかなバグです。
Jon Hanna

81

他の回答を読んだ後、空白のように動作するU + 0000〜U + FFFFの範囲のすべてのUnicode文字を見つける簡単なスクリプトを書きました。どうやら、ブラウザに応じて26または27ありますが、U + 0085とU + FFFEについては意見の相違があります。

これらの文字のほとんどは、通常の空白のように見えることに注意してください。


17
U + 0085「NEL」はUnicodeで空白として定義されていますが、誤って処理された長い歴史があります。U + FFFEはNChar以外の名前とプロパティのない非文字であり、妥当なものによって空白と見なされるべきではありません。そうは言っても、私のブラウザーは両方の点で私と意見が異なります:)
ホッブズ

4
@hobbs U + FFFEも\p{Default Ignorable Code Point}だけでなくでもあり\p{Noncharacter Code Pount}ます。U + 0085は常に\p{Whitespace}コードポイントです。邪悪なのはU + 180E MONGOLIAN VOWEL SEPARATORで、「最近」\p{Whitespace}プロパティを失いました。注\p{Pattern Whitespace}非常に小さく設定され、かつ不変のプロパティ。しかし、そうで\p{Whitespace}はありません。
tchrist

2
FEFFBOMであり、テキスト内の「ゼロ幅の改行なしスペース」のように扱うことができます。FFFEエンディアンスワップに相当するものですか。おそらくそれが、一部のブラウザが空白として扱う理由です。
CodesInChaos 2015

ecma-international.org/ecma-262/6.0/#sec-white-space(Felix Kingの回答からリンク)は、JSソースコードで空白と見なされるようにU + FEFFを明確に呼び出します。U + FFFEはリストに含まれていませんが、これは省略のエラーとして私を襲います。
zwol 2015

1
@zwol、文字U + FFFEがないため、これは省略のエラーではありません。空白として扱うのはバグです。実際、それを有効な文字として扱うことはほとんどの場合バグです。JSの観点によれば、U + 0085は空白ではありませんが、U + 0085を改行しないように特殊なケースにする必要がある仕様は奇妙で、間違いなく仕様のバグです。
Jon Hanna

56

使用している文字が、実際のマイナス記号(ハイフン)よりも実際に長いようです。

 
-

上部はあなたが使用しているものであり、下部はマイナス記号がどうあるべきかです。あなたはすでにそれを知っているようですので、今度はJavascriptがこれを行う理由を見てみましょう。

使用する文字は実際には空白文字であるオガムスペースマークであるため、基本的にスペースと同じものとして解釈されますalert(2+ 40)。つまり、ステートメントはJavascriptのように見えます。

JavaScriptには、このような他の文字があります。完全なリストはWikipediaで確認できます。


この文字について私が気付いた興味深い点の1つは、Google Chrome(および他の可能なブラウザー)がページの上部バーでそれを解釈する方法です。

ここに画像の説明を入力してください

1680内部にブロックがあります。これは実際にはオガムスペースマークの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>'

Javamainメソッド内)

>> 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.

動作する言語:

スキーム

>> (+ 240)
=> 42

C#Main()メソッド内)

Console.WriteLine(2+ 40);

Output: 42

Perl 6

>> ./perl6 -e'say 2+ 40' 
42

34
Ubuntuは問題ではありません。使用しているウィンドウタイトルフォントは
PSkocik 2015

2
Firefox(iceweasel)とdebianのgoogle chromeは、Unicodeの文字をうまく表示するようですが、システムでのunicodeの互換性を確保するために長さにしています。(実際、私が行った最も有用なことは最も単純なものでした:sudo apt-get install unicode何時間もの研究と失敗した試みの後だけですが)
sig_seg_v '20 / 07/20

@PSkocik興味深いことに、私は以前にここでフォントの問題を抱えていたので、それはおそらく可能性があります
michaelpri

51
@PSkocik 「Ubuntuは問題ではありません。使用しているウィンドウタイトルフォントは次のとおりです。」…「Ubuntu」です。
user4642212 2015

1
@PSkocik私は最終的にそれを修正しました:)システムのタイトルバーのフォントを変更する必要があるだけです。
マイケルプリ2015

43

私はそれが何らかの奇妙な理由で空白として分類するという事実で何かをしなければならないと思います:

$ 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
BenjiWiebe 2015

16
これは、unicodeRadovanGarabíkによって(それを待つ...)というUbuntuパッケージからのものです。対応するリポジトリはgithub.com/garabik/unicodeにあります。
PSkocik

OK、githubリンクに感謝します。AFAICT、それはFedoraリポジトリにはありません。
BenjiWiebe

@PSkocik ' '.codePointAt(0)コンソールでは、5760ユニコードをGoogle Nowの5760が得られます。
Royi Namir 2015

6

このように振る舞うキャラクターが他にもいるかどうかも知りたいです。

誰かのコードのセミコロン(U + 003B)をギリシャの疑問符であるU + 037Eにいたずらに置き換えることについて少し前に読んだ覚えがあるようです。

どちらも同じように見えますが(ギリシャ人自身がU + 003Bを使用していると思いますが)、この記事では、もう1つは機能しないと述べています。

ウィキペディアからのこれに関するいくつかの詳細はここにあります: https //en.wikipedia.org/wiki/Question_mark#Greek_question_mark

そして、SO自体からのいたずらとしてこれを使用することに関する(終了した)質問。ただし、AFAIRを最初に読んだ場所ではありません。JavaScriptの 悪ふざけ/ジョーク

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.