是否存在String.toLowerCase()和String.toUpperCase()的JavaScript polyfill实现,或JavaScript中可以与Unicode字符一起使用并且在浏览器之间保持一致的其他方法?
在浏览器中甚至在不同版本的浏览器之间(例如FireFox 54与55)执行以下操作都会产生不同的结果:
document.write(String.fromCodePoint(223).normalize("NFKC").toLowerCase().toUpperCase().toLowerCase())
在Firefox 55中,它为您提供ss
,在Firefox 54中,它为您提供ß
。
通常这很好,Locale之类的机制可以处理很多您想要的情况;但是,当您需要跨平台的一致行为时,例如与像google-cloud-firestore这样的BaaS系统进行对话时,它可以大大简化您实际上在客户端上处理内部数据的交互。
答案 0 :(得分:1)
请注意,此问题似乎只影响Firefox的过时版本,因此,除非您明确需要支持那些旧版本,否则可以选择根本不打扰。您的示例的行为在所有现代浏览器中都相同(因为Firefox中的更改)。可以验证using jsvu + eshost:
$ jsvu # Update installed JavaScript engine binaries to the latest version.
$ eshost -e '"\xDF".normalize("NFKC").toLowerCase().toUpperCase().toLowerCase()'
#### Chakra
ss
#### V8 --harmony
ss
#### JavaScriptCore
ss
#### V8
ss
#### SpiderMonkey
ss
#### xs
ss
但是您问如何解决此问题,所以让我们继续。
https://tc39.github.io/ecma262/#sec-string.prototype.tolowercase的第4步指出:
根据Unicode默认大小写转换算法,将
cuList
设为一个列表,其中元素是toLowercase(cpList)
的结果。
此{em> Unicode默认大小写转换算法在section 3.13 Default Case Algorithms of the Unicode standard中指定。
通过使用来自
SpecialCasing.txt
的映射加上来自UnicodeData.txt
的映射来获得Unicode字符的完整大小写映射,不包括任何可能会冲突的映射。在这些文件中没有映射的任何字符都被认为是映射到自身。[…]
以下规则指定Unicode字符串的默认大小写转换操作。这些规则使用全大小写转换操作
Uppercase_Mapping(C)
,Lowercase_Mapping(C)
和Titlecase_Mapping(C)
,以及基于表述上下文的依赖于上下文的映射,如表3-17所示。对于字符串
X
:
- R1
toUppercase(X)
:将C
中的每个字符X
映射到Uppercase_Mapping(C)
。- R2
toLowercase(X)
:将C
中的每个字符X
映射到Lowercase_Mapping(C)
。
下面是SpecialCasing.txt
的示例,下面添加了我的注释:
00DF ; 00DF ; 0053 0073; 0053 0053; # LATIN SMALL LETTER SHARP S
<code>; <lower>; <title> ; <upper> ; (<condition_list>;)? # <comment>
此行说U + 00DF('ß'
)小写为U + 00DF(ß
),大写字母为U + 0053 U + 0053(SS
)。
下面是UnicodeData.txt
的示例,下面添加了我的注释:
0041 ; LATIN CAPITAL LETTER A; Lu;0;L;;;;;N;;;; 0061 ;
<code>; <name> ; <ignore> ; <lower>; <upper>
此行说U + 0041('A'
)小写到U + 0061('a'
)。它没有显式的大写映射,这意味着它本身是大写的。
这里是UnicodeData.txt
的另一个示例:
0061 ; LATIN SMALL LETTER A; Ll;0;L;;;;;N;; ;0041; ; 0041
<code>; <name> ; <ignore> ; <lower>; <upper>
此行说U + 0061('a'
)大写到U + 0041('A'
)。它没有显式的小写映射,这意味着它本身是小写的。
您可以编写一个脚本来解析这两个文件,按照这些示例读取每一行,并构建小写/大写映射。然后,您可以将这些映射变成一个小的JavaScript库,该库提供符合规范的toLowerCase
/ toUpperCase
功能。
这似乎是很多工作。根据Firefox中的旧行为以及确切的更改(?),您可以将工作限制为SpecialCasing.txt
中的特殊映射。 (我假设您根据您提供的示例在Firefox 55中仅更改了特殊大小写。)
// Instead of…
function normalize(string) {
const normalized = string.normalize('NFKC');
const lowercased = normalized.toLowerCase();
return lowercased;
}
// …one could do something like:
function lowerCaseSpecialCases(string) {
// TODO: replace all SpecialCasing.txt characters with their lowercase
// mapping.
return string.replace(/TODO/g, fn);
}
function normalize(string) {
const normalized = string.normalize('NFKC');
const fixed = lowerCaseSpecialCases(normalized); // Workaround for old Firefox 54 behavior.
const lowercased = fixed.toLowerCase();
return lowercased;
}
我写了一个脚本,用于解析SpecialCasing.txt
并生成一个JS库,该库实现上述lowerCaseSpecialCases
和toLower
的{{1}}功能。这里是:https://gist.github.com/mathiasbynens/a37e3f3138069729aa434ea90eea4a3c根据您的实际用例,您可能根本不需要toUpper
及其对应的正则表达式和映射。这是完整的生成库:
toUpper