跳到主要内容
2024年开发商调查到此,我们希望听到您的意见! 参加2024年开发商调查
第6页,共11页
正文中添加了204个字符
分号
  • 7.1公里
  • 2
  • 30
  • 39

我在现有的有关以下问题的答案中没有看到任何提及星体层代码点或国际化。“大写字母”在使用给定脚本的每种语言中的含义并不相同。

起初,我没有看到任何解决星体层代码点相关问题的答案。那里是一个,但它有点埋了(我想这个会是这样的!)


大多数提议的功能如下所示:

函数大写首字母(str){return str[0].toUpperCase()+str.slice(1);}

然而,一些大小写字符不在BMP(基本多语言平面,代码点U+0到U+FFFF)范围内。例如,以沙漠文本为例:

大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉"); // "𐐶𐐲𐑌𐐼𐐲𐑉"

这里的第一个字符无法大写,因为字符串的数组索引属性不访问“字符”或代码点*。他们访问UTF-16代码单元。切片时也是如此,索引值指向代码单元。

UTF-16代码单元正好是1:1,USV代码点在两个范围内,即U+0到U+D7FF和U+E000到U+FFFF。大多数大小写字符都属于这两个范围,但不是全部。

从ES2015开始,处理这个问题变得更容易了。String.prototype[@@iterator]生成与代码点**对应的字符串。例如,我们可以这样做:

函数大写FirstLetter([first,…rest]){return[first.toUpperCase(),…rest].join('');}大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"

对于较长的字符串,这可能不是非常有效的***-我们实际上不需要迭代余数。我们可以用字符串.原型.代码指向为了得到第一个(可能的)字母,但我们仍然需要确定切片应该从哪里开始。避免迭代余数的一种方法是测试第一个码点是否在BMP之外;如果不是,切片从1开始,如果是,切片从2开始。

函数大写首字母(str){const firstCP=str.codePointAt(0);常量索引=第一个CP>0xFFFF?2 : 1;return String.fromCodePoint(firstCP).toUpperCase()+str.slice(index);}大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"

你可以用位数学代替>0xFFFF(0xFF关闭)在那里,但是用这种方式可能更容易理解,而且两者都会达到同样的目的。

如果必要的话,我们还可以在ES5及以下版本中进一步采用该逻辑来实现这一点。ES5中没有用于处理代码点的内部方法,因此我们必须手动测试第一个代码单元是否是代理****:

函数大写首字母(str){var firstCodeUnit=字符串[0];if(firstCodeUnit<'\uD800'||firstCode Unit>'\uDFFF'){return str[0].toUpperCase()+str.slice(1);}return str.slice(0,2).toUpperCase()+str.slices(2);}大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"

一开始我还提到了国际化的考虑。其中一些很难解释,因为它们不仅需要以下方面的知识什么语言正在被使用,但也可能需要对语言中的单词有特定的知识。例如,爱尔兰有向图“mb”在单词开头大写为“mb”。另一个例子是德语eszett,它从不以单词开头(afaik),但仍然有助于说明问题。小写的eszett(“ß”)大写为“SS”,但“SS”可以小写为“ࢹ”或“SS”-您需要具备德语的课外知识才能知道哪一个是正确的!

这类问题中最著名的例子可能是土耳其语。在土耳其语拉丁语中,i的大写形式是is,而i的小写形式是In——它们是两个不同的字母。幸运的是,我们确实有办法解释这一点:

函数大写FirstLetter([first,…rest],locale){return[first.toLocaleUpperCase(locale),…rest].join('');}大写首字母(“意大利”,“en”)//“意大利”大写首字母(“italya”,“tr”)//“伊塔利亚”

在浏览器中,用户最喜欢的语言标记由导航员语言,可以在中找到按优先顺序排列的列表导航器.语言,可以(通常)使用对象(element.least('[lang]')).lang||YOUR_DEFAULT_HERE在多语言文档中。

在ES2018中引入的支持RegExp中Unicode属性字符类的代理中,我们可以通过直接表示我们感兴趣的字符来进一步清理内容:

函数capitalieFirstLetter(str,locale=navigator.language){return str.replace(/^\p{CWU}/u,char=>char.toLocaleUpperCase(locale));}

这可以稍微调整一下,也可以很好地处理字符串中多个单词的大写。这个CWU公司更改_When_Uppercasedcharacter属性匹配所有代码点,当大写时,这些代码点会更改。我们可以用有标题的有向图字符来尝试,比如荷兰语ij例如:

大写首字母(“ijsselmeer”);//“塞尔米尔”

在撰写本文时(2020年2月),Firefox/Spidermonkey尚未实现过去两年引入的任何RegExp功能。您可以在Kangax兼容表.Babel能够编译RegExp文本,其中包含对等效模式的属性引用,但请注意,生成的代码可能非常庞大。


问这个问题的人很可能与Deseret资本化或国际化无关。但是,意识到这些问题是件好事,因为即使这些问题目前并不令人担忧,最终你也很有可能会遇到它们。它们不是“边缘”案例,或者更确切地说,它们不是按定义边缘案例——在整个国家,大多数人都说土耳其语,将代码单元与代码点混为一谈是一个相当常见的错误源(尤其是表情符号)。字符串和语言都很复杂!


*UTF-16/UCS2的代码单元在某种意义上也是Unicode代码点,例如U+D800在技术上是一个代码点,但这不是它在这里的“意思”。。。某种程度上。。。尽管它变得相当模糊。但是,代理项肯定不是USV(Unicode标量值)。

**尽管如果代理代码单元是“孤立的”,即不是逻辑对的一部分,您仍然可以在这里获得代理。

***也许吧。我还没有测试过它。除非你确定资本化是一个有意义的瓶颈,否则我可能不会费劲——选择你认为最清晰易读的内容。

****这样的函数可能希望测试第一个和第二个代码单元,而不仅仅是第一个,因为第一个单元可能是孤立的代理。例如,输入“\uD800x”将X as-is大写,这可能是预期的,也可能不是预期的。

分号
  • 7.1公里
  • 2
  • 30
  • 39