9

Chcę porównać dwa ciągi w kodzie JavaScript, które są takie same, a jednak operator równości == zwraca wartość false. Jeden ciąg zawiera znak specjalny (np. Duński å).Porównanie ciągów znaków Javascript kończy się niepowodzeniem podczas porównywania znaków Unicode.

kod JavaScript:

var filenameFromJS = "Designhåndbog.pdf"; 
var filenameFromServer = "Designhåndbog.pdf"; 

print(filenameFromJS == filenameFromServer); // This prints false why? 

Rozwiązanie Co pracował dla mnie jest Unicode normalizacji jako slevithan zauważył.

Rozwinąłem moją oryginalną aplikację jsfiddle, aby utworzyć wersję z biblioteką normalizacyjną zasugerowaną przez slevithan. Link: http://jsfiddle.net/GWZ8j/1/.

+0

Zobacz ten artykuł o '' == vs === '' http://stackoverflow.com/questions/359494/javascript-vs-does-it-matter-co-equal-operator-i-use – Steve

+4

@Steve Jeśli oba operandy są tego samego typu, nie ma znaczenia, czy używasz luźnego, czy ścisłego porównania. – PointedEars

Odpowiedz

10

W przeciwieństwie do tego, co powiedzieli niektórzy inni ludzie, nie ma to nic wspólnego z kodowaniem. Zamiast tego, twoje dwa ciągi używają różnych punktów kodowych do renderowania tych samych znaków wizualnych.

Aby rozwiązać ten problem poprawnie, przed porównaniem należy przeprowadzić normalizację Unicode na dwóch ciągach. Na nieszczęście JavaScript nie ma wbudowanej tej funkcji. Oto biblioteka JavaScript, która może przeprowadzić normalizację: https://github.com/walling/unorm

+1

Och, miałem nadzieję, że nie otrzymam tej odpowiedzi :-) Po prostu przegapiłem oczywiste i nie potrzebowałem biblioteki do tego prostego zadania. Dzięki za odpowiedź, spróbuję. – tougher

+0

Masz rację, przegapiłem, że 'CC 8A' jest sekwencją kodu UTF-8 dla' U + 30A COMBINING RING ABOVE', która jest poprzedzona przez 'a'. Drugi ciąg ma "C3 A5", który koduje "U + 00E5 LATIN LATIN LETTER A WITH RING ABOVE" w UTF-8. IIRC, Mac OS preferuje kombinację znaków, podczas gdy inne systemy wolą formę pojedynczego glifu. Powinno być możliwe przekonwertowanie jednego z serwerów, więc nie ma potrzeby posiadania dużej biblioteki po stronie klienta. – PointedEars

+0

PointedEars, niekoniecznie jest to możliwe lub idealne. Np. Możesz nie chcieć wykonać obiegu serwerów tylko po to, aby wykonać porównanie ciągów lub możesz użyć JavaScript na serwerze. @Tougher, Istnieje propozycja dodania normalizacji Unicode do przyszłych wersji JavaScript. Zobacz [strawman: unicode_normalization] (http://wiki.ecmascript.org/doku.php?id=strawman:unicode_normalization). – slevithan

1

UTF-8 to skomplikowana sprawa. Zestaw znaków ma dwa różne kody dla znaków, takich jak á, é itd. Jak już widzisz w wersji zakodowanej za pomocą adresu URL, bajty HEX, z których składa się znak, różnią się dla obu wersji.

Aby uzyskać więcej informacji, zobacz odpowiedź this.

+0

JFTR: Unicode to _nie_ UTF-8. Unicode jest standardem dla zestawu znaków i kilku kodowań; UTF-8 jest jednym z tych kodowań. – PointedEars

+0

Naprawiono błąd @ PointedEars. – user2428118

+0

Teraz mówisz, że UTF-8 był zestawem znaków. Nie jest. Jestem również pewien, że twoje założenie jest fałszywe: sekwencja kodu UTF-8 może nie zaczynać się od 0xCC. – PointedEars

5

Operator równości JavaScript == może się nie udać w następujących okolicznościach. We wszystkich przypadkach jest to błąd programisty. Nie błąd w JavaScript.

  1. Dwa ciągi nie zawierają tej samej liczby i ciągu znaków.

  2. Istnieje spacja lub znaki nowej linii przed, wewnątrz lub po jednym ciągu. Użyj operatora trim() na obydwu i uważnie przyjrzyj się obu ciągom znaków.

  3. Przetwarzanie typu z niespodzianką. Programista porównuje typy danych, które są niezgodne.

  4. Istnieją znaki Unicode, które wyglądają identycznie jak inne znaki Unicode, ale w rzeczywistości są to różne znaki Unicode.

+0

+1, ponieważ ta odpowiedź jest znacznie bardziej informacyjna niż przyjęta i nie zawiera czegoś z nodeJS lub jQuery. – unexist

+0

w tym przypadku numer 4 był winowajcą. – vahanpwns

+0

Inna normalizacja unicod nie dotyczy różnych znaków, ale oznacza, że ​​różne kody punktów kodowych Unicode zostały użyte w odniesieniu do tej samej postaci. – James

0

Miałem ten sam problem.

Dodawanie

<meta charset="UTF-8"> 

do pliku HTML naprawił problem.

W moim przypadku silnik szablonowy wypalał ciąg jsonów w pliku HTML. Ten ciąg był w Unicode.

Podczas gdy szablon był również plikiem w formacie Unicode, mechanizm JS traktował napis, który napisałem, do szablonu jako łańcuch kodowany przez Latin-1, dopóki nie dodałem metatagu.

byłem porównując wpisany ciąg do jednego z obiektów JSON egzemplarze (location.title == "Mühle")