我想知道str.lower()是如何在Python中实现的,所以我克隆了cpython存储库并用grep进行了一些搜索。从unicode_lower
Objects/unicodeobject.c
开始几次跳转后,我在Objects/unicodetype.c
内找到了这个:{/ p>
int _PyUnicode_ToLowerFull(Py_UCS4 ch, Py_UCS4 *res)
{
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
if (ctype->flags & EXTENDED_CASE_MASK) {
int index = ctype->lower & 0xFFFF;
int n = ctype->lower >> 24;
int i;
for (i = 0; i < n; i++)
res[i] = _PyUnicode_ExtendedCase[index + i];
return n;
}
res[0] = ch + ctype->lower;
return 1;
}
我熟悉C,但很不熟悉python的实现方式(但想要改变它!)。我真的不明白发生了什么,所以在这里寻求帮助以获得一些明确的解释。
答案 0 :(得分:1)
您显示的功能中有两个分支。运行哪个分支取决于相关角色的flags
字段的_PyUnicode_TypeRecord
字段。如果设置了EXTENDED_CASE_MASK
位,则运行更复杂的代码,否则使用更简单的版本。
让我们先看一下简单的部分:
res[0] = ch + ctype->lower;
return 1;
这只是将lower
字段的值添加为输入代码点的偏移量,将其分配到res
返回参数的第一位并返回1
(因为它已被使用)一个字符)。
现在更复杂的版本:
int index = ctype->lower & 0xFFFF;
int n = ctype->lower >> 24;
int i;
for (i = 0; i < n; i++)
res[i] = _PyUnicode_ExtendedCase[index + i];
return n;
在此版本中,lower
字段被解释为两个不同的数字。最低16位是index
,而最高位变为n
(要输出的字符数)。然后,代码循环遍历n
数组中_PyUnicode_ExtendedCase
个字符,从index
开始,将它们复制到res
数组中。最后它返回使用的字符数。
需要这个更复杂的代码来处理代表两个字符连字的Unicode代码点的大小写更改(通常由于不明原因,例如因为它们在古代可移动类型打印中会出现在单个类型块上)。如果其他情况下的字符不重叠,则这些连字可能仅存在于单个案例中。例如,字符'fl'
是小写字符'f'
和'l'
的连字。没有大写版本的连字,因此'fl'.upper()
需要返回一个双字符串('FL'
)。