如何实现内置函数str.lower()?

时间:2017-02-01 06:52:07

标签: python

我想知道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的实现方式(但想要改变它!)。我真的不明白发生了什么,所以在这里寻求帮助以获得一些明确的解释。

1 个答案:

答案 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')。