Mengapa 2+ 40 sama dengan 42?

360

Saya bingung ketika seorang kolega menunjukkan saya jajaran JavaScript yang memperingatkan 42 ini.

alert(2+ 40);

Dengan cepat ternyata apa yang tampak seperti tanda minus sebenarnya adalah karakter Unicode yang misterius dengan semantik yang berbeda.

Ini membuat saya bertanya-tanya mengapa karakter itu tidak menghasilkan kesalahan sintaksis ketika ekspresi diuraikan. Saya juga ingin tahu apakah ada lebih banyak karakter berperilaku seperti ini.

GOTO 0
sumber
28
@Elyasin Apakah Anda menyalin / menempel atau mengetik ulang?
user253751
4
Ini juga berfungsi dalam Visual C #. Saat menempelkan karakter aneh ke dalam Visual Studio IDE, atau ketika melengkapi pernyataan dengan mengetik ;, editor cenderung mengubah karakter `` aneh menjadi ruang normal, tetapi jika Anda membatalkan "koreksi otomatis", Anda memiliki perilaku yang sama . Karakter itu memiliki semantik yang sama dengan spasi, bahkan jika itu terlihat seperti tanda hubung atau minus (dalam font biasa).
Jeppe Stig Nielsen
4
Yang sebaliknya bisa terjadi juga. Beberapa bahasa yang mendukung unicode pada pengidentifikasi menerima karakter unicode yang terlihat seperti white space (dengan kata lain, Anda tidak dapat melihatnya); bahkan mungkin untuk memiliki pengidentifikasi yang sama sekali tidak terlihat.
gnasher729
58
(OT) Karena 42 adalah jawaban untuk segalanya?
ivan_pozdeev
4
@Thomas fakta bahwa hasil yang tidak terduga disebabkan oleh karakter Unicode sudah jelas.
GOTO 0

Jawaban:

470

Karakter itu adalah "OGHAM SPACE MARK" , yang merupakan karakter spasi. Jadi kodenya setara dengan alert(2+ 40).

Saya juga ingin tahu apakah ada lebih banyak karakter berperilaku seperti ini.

Setiap karakter Unicode di kelas Zs adalah karakter spasi putih di JavaScript , tetapi tampaknya tidak banyak .

Namun, JavaScript juga memungkinkan karakter Unicode di pengidentifikasi , yang memungkinkan Anda menggunakan nama variabel yang menarik seperti ಠ_ಠ.

Felix Kling
sumber
3
Kotak-dengan-kode-hex menggarisbawahi kotak-dengan-kode-hex. Karakter apa yang dimaksudkan?
user253751
12
@immibis Bagian terakhir dari jawaban ini adalah sebuah emotikon yang tersedia dalam bentuk gambar di disapprovallook.com
Mark S.
3
Perhatikan bahwa bukan hanya Zskarakter yang dianggap sebagai ruang kosong dalam JavaScript. Ada lebih banyak lagi: github.com/mathiasbynens/regexpu/blob/…
Mathias Bynens
20
Reaksi saya ketika ಠ_ಠdapat digunakan sebagai pengidentifikasi di JS: ಠ_ಠ
Chris Cirefice
2
@ChrisCirefice menggarisbawahi diperlakukan sebagai surat yang sudah lama ada dalam bahasa C-style. diperlakukan sebagai surat hanyalah akal sehat, karena itu surat. Ini akan menjadi bug yang jelas jika ಠ_ಠtidak dapat digunakan sebagai pengidentifikasi.
Jon Hanna
81

Setelah membaca jawaban lain, saya menulis skrip sederhana untuk menemukan semua karakter Unicode dalam kisaran U + 0000 – U + FFFF yang berperilaku seperti spasi putih. Sepertinya, ada 26 atau 27 dari mereka tergantung pada browser, dengan perbedaan pendapat tentang U + 0085 dan U + FFFE.

Perhatikan bahwa sebagian besar karakter ini hanya terlihat seperti ruang putih biasa.

GOTO 0
sumber
17
U + 0085 "NEL" didefinisikan sebagai whitespace oleh Unicode tetapi memiliki sejarah panjang yang salah penanganan. U + FFFE adalah noncharacter tanpa nama dan tanpa properti selain NChar dan tidak boleh dianggap sebagai ruang kosong oleh sesuatu yang masuk akal. Yang mengatakan, browser saya tidak setuju dengan saya pada kedua poin :)
hobbs
4
@ hobbs U + FFFE juga a \p{Default Ignorable Code Point}, bukan hanya a \p{Noncharacter Code Pount}. U + 0085 selalu menjadi \p{Whitespace}titik kode. Yang jahat adalah U + 180E MONGOLIAN VOWEL SEPARATOR, yang "baru-baru ini" kehilangan \p{Whitespace}propertinya. Perhatikan bahwa \p{Pattern Whitespace}set jauh lebih kecil, dan properti yang tidak berubah. Tetapi \p{Whitespace}tidak.
tchrist
2
FEFFadalah BOM dan dapat diperlakukan seperti "ruang lebar tanpa putus" dalam teks. FFFEapakah itu setara endian swapped. Mungkin itulah alasan mengapa beberapa browser memperlakukan sebagai spasi.
CodesInChaos
ecma-international.org/ecma-262/6.0/#sec-white-space (sebagaimana ditautkan dari jawaban Felix King) secara khusus memanggil U + FEFF untuk dianggap sebagai ruang kosong dalam kode sumber JS. U + FFFE tidak terdaftar, tetapi menurut saya ini adalah kesalahan kelalaian.
zwol
1
@ zwol, ini bukan kesalahan kelalaian, karena tidak ada karakter U + FFFE. Memperlakukannya sebagai spasi putih adalah bug. Memang, memperlakukannya sebagai karakter yang valid sama sekali adalah bug dalam banyak kasus. U + 0085 bukanlah ruang putih menurut spektra JS, tetapi spesifikasi yang membutuhkan casing khusus U + 0085 untuk tidak menjadi baris baru adalah aneh dan bisa dibilang bug dalam spesifikasi.
Jon Hanna
56

Tampaknya karakter yang Anda gunakan sebenarnya lebih panjang dari tanda minus sebenarnya (tanda hubung).

 
-

Bagian atas adalah apa yang Anda gunakan, bagian bawah adalah tanda minus yang seharusnya. Anda sepertinya sudah tahu itu, jadi sekarang mari kita lihat mengapa Javascript melakukan ini.

Karakter yang Anda gunakan sebenarnya adalah tanda spasi ogham yang merupakan karakter spasi, jadi pada dasarnya diartikan sebagai hal yang sama dengan spasi, yang berarti bahwa pernyataan Anda mirip alert(2+ 40)dengan Javascript.

Ada karakter lain seperti ini di Javascript. Anda dapat melihat daftar lengkapnya di sini di Wikipedia .


Sesuatu yang menarik yang saya perhatikan dari karakter ini adalah cara Google Chrome (dan kemungkinan peramban lain) mengartikannya di bilah atas halaman.

masukkan deskripsi gambar di sini

Itu adalah sebuah blok dengan 1680bagian dalamnya. Itu sebenarnya nomor unicode untuk tanda ruang ogham. Tampaknya ini hanya mesin saya yang melakukan ini, tetapi ini adalah hal yang aneh.


Saya memutuskan untuk mencoba ini dalam bahasa lain untuk melihat apa yang terjadi dan ini adalah hasil yang saya dapatkan.


Bahasa yang tidak berfungsi di:

Python 2 & 3

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

Rubi

>> 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 (di dalam mainmetode)

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

Pergilah

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

Bahasa itu berfungsi dalam:

Skema

>> (+ 240)
=> 42

C # (di dalam Main()metode)

Console.WriteLine(2+ 40);

Output: 42

Perl 6

>> ./perl6 -e'say 2+ 40' 
42
michaelpri
sumber
34
Ubuntu bukan masalah. Font judul jendela yang Anda gunakan adalah.
PSkocik
2
firefox (iceweasel) dan google chrome on debian tampaknya menampilkan unicode char dengan baik, meskipun saya telah berusaha keras untuk memastikan kompatibilitas unicode pada sistem saya. (sebenarnya, hal paling berguna yang saya lakukan adalah yang paling sederhana sudo apt-get install unicode
:,
@ PSkik Menarik, saya punya masalah font di sini sebelumnya, jadi itu mungkin
michaelpri
51
@PSkocik “Ubuntu bukan masalah. Font judul jendela yang Anda gunakan adalah. " ... yang merupakan " Ubuntu ".
user4642212
1
@PSkocik Saya akhirnya memperbaikinya :) Hanya perlu mengubah font bar judul sistem.
michaelpri
43

Saya kira itu harus melakukan sesuatu dengan fakta bahwa untuk beberapa alasan aneh itu diklasifikasikan sebagai spasi putih:

$ 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)
PSkocik
sumber
Jika itu adalah copy dan paste dari terminal Anda, saya ingin tahu di mana Anda menemukan perintah unicode.
BenjiWiebe
16
Ini dari paket Ubuntu bernama (tunggu ...) unicodeoleh Radovan Garabík. Repo yang sesuai ada di github.com/garabik/unicode .
PSkocik
OK, terima kasih atas tautan github. AFAICT, itu bukan di repositori Fedora.
BenjiWiebe
@PSkocik ' '.codePointAt(0)di konsol akan menghasilkan 5760. sekarang google 5760 unicode.
Royi Namir
6

Saya juga ingin tahu apakah ada lebih banyak karakter berperilaku seperti ini.

Sepertinya saya ingat pernah membaca sebuah artikel beberapa waktu lalu tentang mengganti semi-titik dua (U + 003B) yang salah dalam kode seseorang dengan U + 037E yang merupakan tanda tanya Yunani.

Keduanya terlihat sama (sejauh yang saya percaya orang Yunani sendiri menggunakan U + 003B) tetapi artikel ini menyatakan bahwa yang lain tidak akan berfungsi.

Beberapa informasi lebih lanjut tentang ini dari Wikipedia ada di sini: https://en.wikipedia.org/wiki/Question_mark#Greek_question_mark

Dan pertanyaan (tertutup) tentang menggunakan ini sebagai lelucon dari SO itu sendiri. Tidak di tempat saya awalnya membacanya AFAIR: JavaScript Prank / Joke

siang dan
sumber