Tại sao 2+ 40 bằng 42?


360

Tôi đã gặp khó khăn khi một đồng nghiệp chỉ cho tôi dòng JavaScript cảnh báo 42 này.

alert(2+ 40);

Nó nhanh chóng chỉ ra rằng những gì trông giống như một dấu trừ thực sự là một ký tự Unicode phức tạp với ngữ nghĩa rõ ràng khác nhau.

Điều này khiến tôi tự hỏi tại sao nhân vật đó không tạo ra lỗi cú pháp khi biểu thức được phân tích cú pháp. Tôi cũng muốn biết nếu có nhiều nhân vật cư xử như thế này.


28
@Elyasin Bạn đã sao chép / dán hoặc gõ lại?
dùng253751

4
Điều này cũng hoạt động trong Visual C #. Khi dán ký tự lạ vào Visual Studio IDE hoặc khi hoàn thành câu lệnh bằng cách gõ ;, trình soạn thảo có xu hướng thay đổi ký tự `` lạ thành một không gian bình thường, nhưng nếu bạn hoàn tác "tự động sửa" đó, bạn cũng có hành vi tương tự . Nhân vật đó có cùng ngữ nghĩa với một khoảng trắng, ngay cả khi nó trông giống như một dấu gạch nối hoặc dấu trừ (trong các phông chữ thông thường).
Jeppe Stig Nielsen

4
Điều ngược lại cũng có thể xảy ra. Một số ngôn ngữ hỗ trợ unicode trong mã định danh chấp nhận các ký tự unicode trông giống như khoảng trắng (nói cách khác, bạn không thể nhìn thấy chúng); thậm chí có thể có các định danh hoàn toàn vô hình.
gnasher729

58
(OT) Bởi vì 42 là một câu trả lời cho tất cả mọi thứ?
ivan_pozdeev

4
@Thomas thực tế là kết quả không mong muốn được gây ra bởi ký tự Unicode đó đã rõ ràng.
GOTO 0

Câu trả lời:


470

Nhân vật đó là "OGHAM SPACE Mark" , một nhân vật không gian. Vì vậy, mã tương đương với alert(2+ 40).

Tôi cũng muốn biết nếu có nhiều nhân vật cư xử như thế này.

Bất kỳ ký tự Unicode nào trong lớp Zs đều là ký tự khoảng trắng trong JavaScript , nhưng dường như không có nhiều .

Tuy nhiên, JavaScript cũng cho phép các ký tự Unicode trong mã định danh , cho phép bạn sử dụng các tên biến thú vị như ಠ_ಠ.


3
Box-with-a-hex-code gạch dưới hộp-with-a-hex-code. Nó có nghĩa là nhân vật nào?
dùng253751

12
@immibis Phần cuối cùng của câu trả lời này là một biểu tượng cảm xúc có sẵn ở dạng hình ảnh tại disapprovallook.com
Mark S.

3
Lưu ý rằng không chỉ các Zský tự được coi là khoảng trắng trong JavaScript. Có nhiều hơn: github.com/mathiasbynens/regapidu/blob/
Kẻ

20
Phản ứng của tôi khi ಠ_ಠcó thể được sử dụng như một định danh trong JS: ಠ_ಠ
Chris Cirefice

2
@ChrisCirefice gạch dưới được coi là một chữ cái đã có từ lâu trong các lang theo kiểu C. được coi là một bức thư chỉ là lẽ thường, vì đó là một bức thư. Nó sẽ là một lỗi rõ ràng nếu ಠ_ಠkhông thể được sử dụng như một định danh.
Jon Hanna

81

Sau khi đọc các câu trả lời khác, tôi đã viết một tập lệnh đơn giản để tìm tất cả các ký tự Unicode trong phạm vi U + 0000, U + FFFF hoạt động giống như khoảng trắng. Có vẻ như, có 26 hoặc 27 trong số chúng tùy thuộc vào trình duyệt, với những bất đồng về U + 0085 và U + FFFE.

Lưu ý rằng hầu hết các nhân vật này trông giống như một khoảng trắng thông thường.


17
U + 0085 "NEL" được định nghĩa là khoảng trắng bởi Unicode nhưng có một lịch sử lâu dài bị xử lý sai. U + FFFE là một loại không có vi khuẩn không có tên và không có thuộc tính ngoài NChar và không nên được coi là khoảng trắng bởi bất cứ điều gì hợp lý. Điều đó nói rằng, trình duyệt của tôi không đồng ý với tôi ở cả hai điểm :)
hobbs 20/07/2015

4
@hobbs U + FFFE cũng là một \p{Default Ignorable Code Point}, không chỉ là a \p{Noncharacter Code Pount}. U + 0085 luôn là một \p{Whitespace}điểm mã. Kẻ thủ ác là U + 180E MONGOLIAN VOWEL SEPARATOR, mà gần đây đã bị mất \p{Whitespace}tài sản. Lưu ý rằng đó \p{Pattern Whitespace}là một tập hợp nhỏ hơn nhiều và một thuộc tính bất biến. Nhưng \p{Whitespace}không phải.
tchrist

2
FEFFlà BOM và có thể được coi là "không gian không phá vỡ chiều rộng bằng không" trong các văn bản. FFFELà nó endian hoán đổi tương đương. Có lẽ đó là lý do một số trình duyệt coi là khoảng trắng.
CodeInChaos

ecma-i Intl.org/ecma-262/6.0/#sec-white-space (như được liên kết từ câu trả lời của nhà vua Felix) đặc biệt gọi U + FEFF để được coi là khoảng trắng trong mã nguồn JS. U + FFFE không được liệt kê, nhưng điều đó gây cho tôi một lỗi thiếu sót.
zwol 21/07/2015

1
@zwol, đó không phải là lỗi thiếu sót, vì không có ký tự U + FFFE. Coi nó như khoảng trắng là một lỗi Thật vậy, coi nó như một nhân vật hợp lệ là một lỗi trong hầu hết các trường hợp. U + 0085 không phải là khoảng trắng theo phổ JS, nhưng thông số kỹ thuật đó đòi hỏi phải có lớp vỏ đặc biệt của U + 0085 để không phải là một dòng mới rất kỳ quái và được cho là một lỗi trong thông số kỹ thuật.
Jon Hanna

56

Dường như ký tự mà bạn đang sử dụng thực sự dài hơn ký hiệu trừ thực tế (dấu gạch nối).

 
-

Trên cùng là những gì bạn đang sử dụng, dưới cùng là những gì dấu trừ nên được. Bạn dường như đã biết điều đó rồi, vì vậy bây giờ hãy xem tại sao Javascript làm điều này.

Ký tự mà bạn sử dụng thực sự là dấu không gian ogham là ký tự khoảng trắng, do đó, về cơ bản nó được hiểu là giống như một khoảng trắng, có nghĩa là câu lệnh của bạn trông giống như alert(2+ 40)Javascript.

Có những nhân vật khác như thế này trong Javascript. Bạn có thể xem danh sách đầy đủ ở đây trên Wikipedia .


Một điều thú vị tôi nhận thấy về nhân vật này là cách Google Chrome (và có thể các trình duyệt khác) diễn giải nó trong thanh trên cùng của trang.

nhập mô tả hình ảnh ở đây

Nó là một khối với 1680bên trong của nó. Đó thực sự là số unicode cho dấu không gian ogham. Nó chỉ là máy của tôi làm điều này, nhưng nó là một điều kỳ lạ.


Tôi quyết định thử điều này bằng các ngôn ngữ khác để xem điều gì xảy ra và đây là kết quả mà tôi nhận được.


Ngôn ngữ không hoạt động trong:

Python 2 & 3

>> 2+ 40
  File "<stdin>", line 1
    2+ 40
        ^
SyntaxError: invalid character in identifier

Hồng ngọc

>> 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 (bên trong mainphương thức)

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

Đi

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

Ngôn ngữ nó hoạt động trong:

Kế hoạch

>> (+ 240)
=> 42

C # (bên trong Main()phương thức)

Console.WriteLine(2+ 40);

Output: 42

Perl 6

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

34
Ubuntu không phải là vấn đề. Phông chữ tiêu đề cửa sổ bạn đang sử dụng là.
PSkocik

2
firefox (iceweasel) và google chrome trên debian dường như chỉ hiển thị char unicode tốt, mặc dù tôi đã cố gắng đảm bảo khả năng tương thích unicode trên hệ thống của mình. (thực ra, điều hữu ích nhất tôi đã làm là đơn giản nhất: sudo apt-get install unicodemặc dù chỉ sau nhiều giờ nghiên cứu và thất bại)
sig_seg_v

@PSkocik Thật thú vị, tôi đã gặp vấn đề về phông chữ ở đây trước đây, vì vậy rất có thể
michaelpri

51
@PSkocik Ubuntu Ubuntu không phải là vấn đề. Phông chữ tiêu đề cửa sổ bạn đang sử dụng là. Đây là loại Ubuntu Ubuntu .
dùng4642212

1
@PSkocik Cuối cùng tôi đã sửa nó :) Chỉ cần thay đổi phông chữ thanh tiêu đề hệ thống.
michaelpri

43

Tôi đoán nó phải làm một cái gì đó với thực tế là vì một lý do kỳ lạ nào đó, nó được phân loại là khoảng trắng:

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

Nếu đó là một bản sao và dán từ thiết bị đầu cuối của bạn, tôi muốn biết nơi bạn tìm thấy lệnh unicode.
BenjiWiebe

16
Đó là từ gói Ubuntu có tên (chờ nó ...) unicodecủa Radovan Garabík. Repo tương ứng có tại github.com/garabik/unicode .
PSkocik

OK, cảm ơn vì liên kết github. AFAICT, nó không có trong repos Fedora.
BenjiWiebe

@PSkocik ' '.codePointAt(0)tại bảng điều khiển sẽ mang lại 5760. bây giờ google 5760 unicode.
Royi Namir

6

Tôi cũng muốn biết nếu có nhiều nhân vật cư xử như thế này.

Tôi dường như nhớ lại việc đọc một đoạn trước về việc thay thế một cách tinh nghịch các dấu chấm phẩy (U + 003B) trong mã của ai đó bằng U + 037E là dấu chấm hỏi của Hy Lạp.

Cả hai đều trông giống nhau (đến mức tôi tin rằng chính người Hy Lạp sử dụng U + 003B) nhưng bài viết này nói rằng cái kia sẽ không hoạt động.

Một số thông tin khác về điều này từ Wikipedia có ở đây: https://en.wikipedia.org/wiki/Question_mark#Galet_question_mark

Và một câu hỏi (đóng) về việc sử dụng điều này như trò đùa từ chính SO. Không phải nơi ban đầu tôi đọc nó AFAIR: JavaScript Prank / Joke

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.