29

在一些库的代码中(例如AngularJS,链接指向代码中的特定行),我可以看到使用自定义大小写转换函数而不是标准函数。假设在土耳其语言环境的浏览器中,标准函数不能按预期工作是合理的:

console.log("SCRIPT".toLowerCase()); // "scrıpt"
console.log("script".toUpperCase()); // "SCRİPT"

但这是真的还是曾经如此?浏览器真的会这样吗?如果是这样,他们中的哪一个会这样做?node.js 呢?其他 JS 引擎?

toLocaleLowerCaseand方法的存在toLocaleUpperCase意味着toLowerCaseandtoUpperCase是区域不变的,不是吗?

具体来说,对于哪些浏览器,Angular 团队会在代码中保留此检查:if ('i' !== 'I'.toLowerCase())...


如果您的浏览器(设备)使用土耳其语或阿塞拜疆语言环境,请运行此代码段并在您发现问题确实存在时给我写信。

if ('i' !== 'I'.toLowerCase()) {
  document.write('Ooops! toLowerCase is locale-sensitive in your browser. ' +
    'Please write your user-agent in the comments to this question: ' +
    navigator.userAgent); 
} else {
  document.write('toLowerCase isn\'t locale-sensitive in your browser. ' +
    'Everything works as expected!');
}
<html lang="tr">

4

2 回答 2

16

注意:请注意,我无法测试它!


根据ECMAScript 规范

String.prototype.toLowerCase ( )

[...]

出于此操作的目的,字符串的 16 位代码单元被视为 Unicode 基本多语言平面中的代码点。代理代码点直接从 S 转移到 L,无需任何映射。

结果必须根据 Unicode 字符数据库中的大小写映射得出(这不仅明确包括 UnicodeData.txt 文件,包括Unicode 2.1.8 及更高版本中随附的 SpecialCasings.txt 文件)。

[...]

String.prototype.toLocaleLowerCase ( )

此函数的工作方式与 toLowerCase 完全相同,只是它的结果旨在为主机环境的当前语言环境生成正确的结果,而不是独立于语言环境的结果。只有在该语言的规则与常规 Unicode 大小写映射冲突的少数情况下(例如土耳其语)才会有所不同。

[...]

并根据Unicode 字符数据库特殊大小写

[...]

格式

此文件中的条目采用以下机器可读格式:

<code>; <lower>; <title>; <upper>; (<condition_list>;)? # <comment>

无条件映射

[...]

用点为 I 保留规范等价。突厥语在下面处理。

0130; 0069 0307; 0130; 0130; # LATIN CAPITAL LETTER I WITH DOT ABOVE

[...]

语言敏感映射 这些字符的完整大小写映射取决于语言,也可能取决于上下文(哪些字符出现在之前或之后)。有关详细信息,请参阅此文件的标题和 Unicode 标准。

立陶宛语

立陶宛语中的点在小写 i 中后跟重音符号。

删除“i”后的 DOT ABOVE 并使用大写或首字母大写

0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE

当上面有更多重音符号时,在小写大写字母 I's 和 J's 时在上面引入一个明确的点。(立陶宛语中使用的重音:grave、accent、tilde above 和 ogonek)

0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I

004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J

012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK

00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE

00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE

0128; 0069 0307 0303; 0128; 0128; lt; #LATIN CAPITAL LETTER I WITH TILDE

土耳其语和阿塞拜疆语

我和i-dotless;I-dot 和 i 是土耳其语和阿塞拜疆语中的大小写对 以下规则处理这些情况。

0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE

0130; 0069; 0130; 0130; az; # LATIN CAPITAL LETTER I WITH DOT ABOVE

小写时,去掉序列i+dot_above中的dot_above,变成i。这与规范等效的 I-dot_above 的行为相匹配

0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE

0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE

小写时,除非 I 在 dot_above 之前,否则它会变成无点 i。

0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I

0049; 0131; 0049; 0049; az Not_Before_Dot; # LATIN CAPITAL LETTER I

大写时,i 变成点大写 I

0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I

0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I

注意:以下案例已经在 UnicodeData.txt 文件中。

0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I

EOF

此外,根据JavaScript for Absolute Beginners (by Terry McNavage)

> "I".toLowerCase() // "i"
> "i".toUpperCase() // "I"
> "I".toLocaleLowerCase() // "<dotless-i>"
> "i".toLocaleUpperCase() // "<dotted-I>"

注意toLocaleLowerCase()根据您的操作系统设置toLocaleUpperCase()转换大小写。您必须将这些设置更改为土耳其语才能使之前的示例正常工作。或者相信我的话!

根据bobince 对将 JavaScript 字符串转换为小写的评论?问题

Accept-Language并且navigator.language是两个完全独立的设置。Accept-Language反映了用户对他们希望在网页中接收哪些语言的偏好(不幸的是,JS 无法访问此设置)。navigator.language仅反映安装了 Web 浏览器的本地化版本,一般不应用于任何用途。这两个值都与系统语言环境无关,系统语言环境决定了 toLocaleLowerCase() 将做什么;这是超出浏览器首选项范围的操作系统级别设置。


因此,设置lang="tr-TR"html不会反映真实的测试用例,因为它是重现特殊外壳示例所需的操作系统设置。

我认为只有小写 dotted-I 或大写 dotless-i 在使用toLowerCase()or时是特定于语言环境的toUpperCase()

根据那些可靠/官方的消息来源,我认为你是对的:'i' !== 'I'.toLowerCase()总是会评估为假。

但是,正如我所说,我无法在这里测试它。

于 2015-03-20T19:47:56.337 回答
14

任何遵循 ECMA-262 5.1 标准的 JS 实现都必须实现String.prototype.toLocaleLowerCaseString.prototype.toLocaleUpperCase

并且根据标准toLocaleLowerCase,应该根据特定于语言环境的映射将字符串转换为小写映射。

其中 astoLowerCase转换为 unicode 映射定义的小写字符串。

对于大多数语言toLocaleLowerCasetoLowerCase给出相同的结果。但是对于某些语言,例如土耳其语,大小写映射不遵循 unicode 映射,因此toLowerCasetoLocaleLowerCase给出不同的结果。

您使用的库/框架(Jquery、Angular、Node 等等)没有任何区别。它是在你用来运行你的 JS 库的 JS 实现中产生和改变的。

出于所有实际目的,可以准确地得出结论,Node/Angular 或任何其他 JS 库和框架在处理字符串时的行为完全相同(只要它们被实现 ECMA-262 3 及更高版本的 JS 引擎使用)。话虽如此,我确信许多框架扩展了字符串对象以添加更多功能,但ECMA-262 5.1 定义的基本属性和函数始终存在并且行为完全相同。

要了解更多信息:http: //www.ecma-international.org/ecma-262/5.1/#sec-15.5.4.17

就浏览器而言,所有现代浏览器都在其 JS 引擎中实现了 ECMA-262 5.1 标准。我不确定 Node,但从我对 Node 的有限接触来看,我认为他们也使用根据 ECMA-262 5.1 标准实现的 JS。

于 2015-03-01T09:52:35.017 回答