比较 unicode 字符时,Javascript 字符串比较失败
Posted
技术标签:
【中文标题】比较 unicode 字符时,Javascript 字符串比较失败【英文标题】:Javascript string comparison fails when comparing unicode characters 【发布时间】:2012-06-04 01:32:14 【问题描述】:我想比较 javascript 中两个相同的字符串,但相等运算符 ==
返回 false。一个字符串包含一个特殊字符(例如丹麦语å
)。
JavaScript 代码:
var filenameFromJS = "Designhåndbog.pdf";
var filenameFromServer = "Designhåndbog.pdf";
print(filenameFromJS == filenameFromServer); // This prints false why?
解决方案 对我有用的是 slevthan 指出的 unicode 规范化。
我分叉了我原来的 jsfiddle 以使用 slevthan 建议的规范化库制作一个版本。链接:http://jsfiddle.net/GWZ8j/1/.
【问题讨论】:
查看这篇关于==
与===
***.com/questions/359494/…的文章
@Steve 当两个操作数属于同一类型时,使用松散比较还是严格比较都没关系。
这也很有用:joelonsoftware.com/2003/10/08/…(每个开发者都需要了解的关于 unicode 和字符集的知识)
【参考方案1】:
与这里的其他人所说的不同,这与编码无关。相反,您的两个字符串使用不同的代码点来呈现相同的视觉字符。
要正确解决此问题,您需要在比较两个字符串之前对它们执行 Unicode 规范化。不幸的是,JavaScript 没有内置此功能。这是一个可以为您执行规范化的 JavaScript 库:https://github.com/walling/unorm
【讨论】:
哦,我希望不要得到这个答案 :-) 我只是错过了显而易见的事情,并且不需要图书馆来完成这个简单的任务。谢谢你的回答,我试试看。 你说得对,我错过了CC 8A
是U+30A COMBINING RING ABOVE
的UTF-8编码序列,前面是a
。另一个字符串有C3 A5
,它用UTF-8 编码U+00E5 LATIN SMALL LETTER A WITH RING ABOVE
。 IIRC,Mac OS 更喜欢组合字符,而其他操作系统更喜欢单字形形式。不过,应该可以让服务器转换任何一个,因此不需要大型客户端库。
PointedEars,这不一定是可能的或理想的。例如,您可能不想为了执行字符串比较而进行服务器往返,或者您可能在服务器上使用 JavaScript。 @Tougher,有一个提议将 Unicode 规范化添加到 JavaScript 的未来版本中。见strawman:unicode_normalization。【参考方案2】:
JavaScript 相等运算符==
在以下情况下会出现故障。在所有情况下,它都是程序员错误。不是 JavaScript 中的错误。
这两个字符串不包含相同数量和序列的字符。
在一个字符串之前、之中或之后有空格或换行符。对两者都使用 trim() 运算符并仔细查看两个字符串。
令人惊讶的类型转换。程序员正在比较不兼容的数据类型。
有些 unicode 字符看起来与其他 unicode 字符相同,但实际上是不同的 unicode 字符。
【讨论】:
+1,因为这个答案比接受的答案更丰富,并且不包含 nodeJS 或 jQuery 的内容。 在这种情况下,4号是罪魁祸首 不同的 unicode 规范化不是关于不同的字符,而是意味着使用不同的 unicode 代码点序列来指代同一个字符。【参考方案3】:UTF-8 是一个复杂的东西。字符集有两个不同的字符代码,例如 á、é 等。正如您在 URL 编码版本中看到的那样,两个版本的字符的 HEX 字节不同。
有关更多信息,请参阅this 答案。
【讨论】:
JFTR:Unicode 不是 UTF-8。 Unicode 是一个字符集和几种编码的标准; UTF-8 就是其中一种编码。 现在你说 UTF-8 是一个字符集。它不是。我也相当肯定您的前提是错误的:UTF-8 代码序列可能不以 0xCC 开头。 你说得对,我应该把它称为“编码”,就像它出现的那样 (w3.org/TR/html4/charset.html)。 HTML 代码是<meta charset=UTF-8>
(HTML5) 或 <meta http-equiv=Content-Type content='text/html; charset=UTF-8'>
,但是这有点误导。
是的,我想我们将不得不在很长一段时间内忍受早期 Internet 草案中的错误(我说的是 RFC 822 和这里的朋友)。
我对 0xCC 的看法是错误的。 Richard Ishida's excellent Unicode tools 证明了这一点。【参考方案4】:
我遇到了同样的问题。
添加
<meta charset="UTF-8">
到 HTML 文件修复了问题。
在我的例子中,模板引擎将一个 json 字符串烘焙到 HTML 文件中。这个字符串是 unicode 格式的。
虽然模板也是一个 unicode 文件,但 JS 引擎将我写入模板的字符串视为 latin-1 编码字符串,直到我添加了元标记。
我正在将输入的字符串与其中一个 JSON 对象项 (location.title == "Mühle"
) 进行比较
【讨论】:
【参考方案5】:让浏览器为您规范化 unicode。这种方法对我有用:
function normalizeUnicode(s)
let div = $('<div style="display: none"></div>').html(s).appendTo('body');
let res = div.html();
div.remove();
return res;
normalizeUnicode(unicodeVal1) == normalizeUnicode(unicodeVal2)
【讨论】:
以上是关于比较 unicode 字符时,Javascript 字符串比较失败的主要内容,如果未能解决你的问题,请参考以下文章