String.toLowerCase() 实际上是如何工作的?如何手动创建该功能?



要设置Stringlowercase,我们只需要调用函数toLowerCase()即可。但是,对于我现在正在使用的语言,没有这样的功能,所以我需要自己创建一个。Javascript如何能够手动实现这一点?

对于ASCII,它只是一个简单的"取字母的字符代码,加上32,你就完成了,因为这就是ASCII中的数字代码的排列方式",但你问的是JavaScripttoLowerCase(),这是一个Unicode函数:事情很复杂。

在 unicode 领域,不仅有单个"大写 -> 小写"映射,还有"这个大写字符实际上是这个其他大写字符的变体"字母,以及"这个看起来大写的字符实际上是一个连字,需要分解为多个小写字符",以及"这个大写字符没有小写等效项"所以在现实中,一个适当的toLowerCase函数必须检查 Unicode 大小写数据,以确定如何将字符串中的每个字符转换为其小写等效字符(如果存在(。

例如,对于拉丁字符(通常称为"ascii"字符,但事实并非如此:ASCII 是一组正好 128 个代码,其中相当多是不可打印的(,我们看到这样的数据:

...
0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061;
...

所以我们看到A,带有十六进制代码0x41,在代码 0x61 处有一个小写等价物:

...
0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041
...

所以对于这组代码,规则是:

if (0x41 <= codepoint <= 0x5A) newcodepoint = codepoint + 0x20

但是,仅稍微向下移动列表,我们看到:

...
012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B;
012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A
...

在这里,小写和大写变体彼此相邻。加或减 32 确实是非常错误的。相反,我们需要使用规则

if (0x0100 <= codepoint <= 0x012E) newcodepoint = codepoint + 1

所以一个真正的toLowerCase是一个三阶段函数:

  1. 找到你正在查看的角色所在的"映射集",然后
  2. 将该集合的规则应用于大写和小写之间的映射,请注意,即使此集合存在,它也可能只映射一个方向,因此
  3. 如果找不到映射,请遵循官方 Unicode 建议执行的操作。

另外,请注意,在步骤 1 中,我们可能需要做比您想象的更多的工作,因为并非每种语言都允许将每个字母盲目映射到单个大写或小写:根据字母在单词中的位置,可能会有不同的大写或小写等效项。只是为了让事情变得更加有趣。

文本转换很难,这就是为什么你几乎从不尝试实现自己的版本:这是乍一看似乎非常简单的主题之一,但当你真正坐下来研究一下它时,结果发现它非常困难,你真的需要一整个团队来编写一个函数, 只是为了覆盖每个边缘情况,并且没有因为您碰巧错过了关于一些很少使用的角色的小规则而溜进的错误。

因此,要回答您关于如何为您正在使用的语言实现这一点的问题:您没有。查找支持您的语言的字符串库,并针对您的示例查找toLowerCase()无法正常工作的浏览器问题,因为这些是需要在其实现中修复的错误。

@VLAZ提到的此示例代码,并且没有硬编码差异 (26(。 希望这有帮助。

const toLowerCase = str => {
let updated = "";
const [upp_start, upp_end, low_start] = "AZa"
.split("")
.map(x => x.charCodeAt(0));
for (let i = 0; i < str.length; i++) {
const charCode = str[i].charCodeAt(0);
const diff =
charCode >= upp_start && charCode <= upp_end ? low_start - upp_start : 0;
updated = updated + String.fromCharCode(charCode + diff);
}
return updated;
};
console.log(toLowerCase("Stack"));
console.log(toLowerCase("OVERFLOW"));

最新更新