2+ 40이 42 인 이유는 무엇입니까?


360

동료가이 JavaScript 알림 라인을 보여줄 때 당황했습니다 42.

alert(2+ 40);

빼기 부호처럼 보이는 것이 실제로 의미가 다른 비전의 유니 코드 문자라는 것이 금방 밝혀졌습니다.

이것은 표현식이 구문 분석 될 때 해당 문자가 구문 오류를 생성하지 않는 이유를 궁금하게했습니다. 또한 이와 같이 동작하는 문자가 더 있는지 알고 싶습니다.


28
@Elyasin 복사 / 붙여 넣기 또는 다시 입력 했습니까?
user253751

4
이것은 Visual C #에서도 작동합니다. 이상한 문자를 Visual Studio IDE에 붙여 넣거나을 입력하여 명령문을 완료 할 때 ;편집기는 이상한``문자를 일반 공간으로 변경하는 경향이 있지만 해당 "자동 수정"을 실행 취소하면 동일한 동작이 발생합니다. . 하이픈이나 마이너스 (보통 글꼴)처럼 보이더라도 해당 문자는 공백과 동일한 의미를 갖습니다.
Jeppe Stig Nielsen

4
반대의 경우도 발생할 수 있습니다. 식별자에서 유니 코드를 지원하는 일부 언어는 공백처럼 보이는 유니 코드 문자를 허용합니다 (즉, 볼 수 없음). 완전히 보이지 않는 식별자를 가질 수도 있습니다.
gnasher729

58
(OT) 42는 모든 것에
ivan_pozdeev

4
@Thomas 해당 유니 코드 문자로 인해 예기치 않은 결과가 발생했다는 사실은 이미 명확했습니다.
GOTO 0

답변:


470

해당 문자는 공백 문자 인 "OGHAM SPACE MARK" 입니다. 따라서 코드는와 동일합니다 alert(2+ 40).

또한 이와 같이 동작하는 문자가 더 있는지 알고 싶습니다.

ZS 클래스의 모든 유니 코드 문자는 자바 스크립트에서 공백 문자입니다 , 하지만 많은 수는 없을 것 같다 .

그러나 JavaScript는 식별자에 유니 코드 문자를 허용하므로 와 같은 흥미로운 변수 이름을 사용할 수 있습니다 ಠ_ಠ.


3
16 진수 코드로 된 밑줄은 16 진수 코드로 된 밑줄입니다. 그것은 어떤 성격을 의미합니까?
user253751

12
@immibis이 답변의 마지막 부분은 disapprovallook.com
Mark S.

3
ZsJavaScript에서는 문자 만이 공백으로 간주 되지 않습니다 . 더 있습니다 github.com/mathiasbynens/regexpu/blob/...
마티아스 Bynens

20
ಠ_ಠJS에서 식별자로 사용될 수있을 때의 반응 : ಠ_ಠ
Chris Cirefice

2
문자로 취급되는 @ChrisCirefice 밑줄은 C 스타일 언어에서 오랫동안 사용되어 왔습니다. 편지로 취급되는 것은 편지이기 때문에 상식입니다. ಠ_ಠ식별자로 사용될 수 없다면 분명한 버그 일 것 입니다.
존 한나

81

다른 답변을 읽은 후 공백처럼 동작하는 U + 0000 – U + FFFF 범위의 모든 유니 코드 문자를 찾는 간단한 스크립트를 작성했습니다. 보이는 것처럼 브라우저에 따라 U + 0085와 U + FFFE에 대해 의견이 일치하지 않는 26 개 또는 27 개가 있습니다.

이러한 문자의 대부분은 일반적인 공백처럼 보입니다.


17
U + 0085 "NEL"은 유니 코드에 의해 공백으로 정의되었지만 오랫동안 잘못 처리 된 기록이 있습니다. 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
FEFF는 BOM이며 텍스트 내에서 "제로 폭의 중단없는 공간"으로 취급 될 수 있습니다. FFFE그것은 엔디안 스왑 동등한 것입니다. 아마도 이것이 일부 브라우저가 공백으로 취급하는 이유 일 것입니다.
코드 InChaos

ecma-international.org/ecma-262/6.0/#sec-white-space(Felix King의 답변과 연결됨)는 특히 U + FEFF를 JS 소스 코드의 공백으로 간주합니다. U + FFFE는 표시되지 않지만 누락 된 오류로 표시됩니다.
zwol

1
@zwol, 문자 U + FFFE가 없기 때문에 생략 오류가 아닙니다. 공백으로 처리하는 것은 버그입니다. 실제로, 그것을 유효한 문자로 취급하는 것은 대부분의 경우 버그입니다. JS spect에 따르면 U + 0085는 공백이 아니지만 U + 0085를 새 줄이 아니어야하는 특수 사양을 요구하는 사양은 기괴하고 사양의 버그입니다.
존 한나

56

사용중인 문자가 실제 빼기 기호 (하이픈)보다 실제로 더 긴 것 같습니다.

 
-

위쪽은 사용중인 것이고 아래쪽은 빼기 부호입니다. 이미 알고 계신 것 같습니다. 이제 Javascript가 왜이 기능을 사용하는지 봅시다.

사용하는 문자는 실제로 공백 문자 인 ogham 스페이스 마크 이므로 기본적으로 공백과 동일한 것으로 해석되므로 명령문이 alert(2+ 40)Javascript 처럼 보입니다 .

Javascript에는 이와 같은 다른 문자가 있습니다. Wikipedia 에서 전체 목록을 볼 수 있습니다 .


이 캐릭터에 대해 흥미로운 점은 Chrome (및 가능한 다른 브라우저)이 페이지 상단 막대에서이를 해석하는 방식입니다.

여기에 이미지 설명을 입력하십시오

1680안에 있는 블록입니다 . 실제로는 오그 햄 스페이스 마크의 유니 코드 번호입니다. 이 작업을 수행하는 기계 일 뿐이지 만 이상한 일입니다.


나는 이것을 다른 언어로 시도하여 어떤 일이 일어나고 나는 이것이 얻은 결과인지 확인하기로 결정했습니다.


작동하지 않는 언어 :

파이썬 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>'

자바 ( 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

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

펄 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

펄 6

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

34
우분투는 문제가되지 않습니다. 사용중인 창 제목 글꼴이 있습니다.
PSkocik

2
데비안의 firefox (iceweasel)와 google chrome은 유니 코드 문자를 잘 표시하는 것처럼 보이지만 시스템에서 유니 코드 호환성을 보장하기 위해 많은 시간을 투자했습니다. (실제로, 내가 한 가장 유용한 것은 가장 간단한 것입니다. sudo apt-get install unicode몇 시간의 연구와 실패한 시도 후에도)
sig_seg_v

그 가능성이 아마 그래서 @PSkocik의 흥미, 내가 전에 여기에 글꼴 문제가 있었다
michaelpri

51
@PSkocik “우분투는 문제가되지 않습니다. 사용중인 창 제목 글꼴이 있습니다. " …“ 우분투 ”입니다.
user4642212

1
@ PSkocik 나는 마침내 그것을 고쳤다 :) 시스템 제목 표시 줄 글꼴을 변경해야했습니다.
michaelpri

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

16
unicodeRadovan Garabík 의 우분투 패키지 (기다려라 ...) 에서 나온 것입니다. 해당 리포지토리github.com/garabik/unicode에 있습니다.
PSkocik

좋아, github 링크 주셔서 감사합니다. AFAICT, 그것은 Fedora 저장소에 없습니다.
BenjiWiebe

' '.codePointAt(0)콘솔에서 @PSkocik 은 5760을 생성합니다. 이제 Google 5760 유니 코드입니다.
Royi Namir

6

또한 이와 같이 동작하는 문자가 더 있는지 알고 싶습니다.

누군가의 코드에서 세미콜론 (U + 003B)을 그리스어 물음표 인 U + 037E로 잘못 대체하는 것에 대해 잠시 동안 읽은 것을 기억합니다.

둘 다 동일하게 보입니다 (그리스인들이 U + 003B를 사용한다고 생각하는 정도까지). 그러나이 기사에서는 다른 것이 작동하지 않을 것이라고 언급했습니다.

Wikipedia에서 이에 대한 추가 정보는 다음과 같습니다. https://en.wikipedia.org/wiki/Question_mark#Greek_question_mark

그리고 이것을 SO 자체의 장난으로 사용하는 것에 대한 (닫힌) 질문. 내가 AFAIR를 처음 읽은 곳이 아닙니다 : JavaScript Prank / Joke

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.