转换为 upper/lowercase 后,字符串会变短吗?
Can a string ever get shorter when converted to upper/lowercase?
转换为大写或小写时,字符串可能会变长(根据 Unicode 代码点)。例如,'ß'.upper()
的计算结果为 'SS'
。但是有没有变短的琴弦?也就是说,是否存在一个字符串 s
使得表达式
len(s.lower()) < len(s) or len(s.upper()) < len(s)
计算为 True
?
我认为这可能取决于实现。我会根据 CPython 源码回答。
在我看来,有两种可能的情况,在字符串上调用 lower
可以使其更短。
- 两个相邻的 Unicode 点的某种组合被转换为一个 Unicode 点。
- 单个 Unicode 点被转换为空字符串。
我们可以通过检查内部小写转换函数的类型签名来确定情况 1 是否可能。在 Objects/unicodectype.c.
中
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;
}
我不是 100% 理解这段代码,但我观察到第一个参数 ch
是单个 Unicode 点。由于它只对单个字符而不是字符组合进行操作,因此情况 1 似乎已被排除;代码点的组合不会变成更小的序列。
除此之外,我们可以通过迭代到 sys.maxunicode
并查看是否有任何单个值在降低后的长度为零来确定情况 2 是否曾经发生过。
>>> import sys
>>> unicode_chars = list(map(chr, range(sys.maxunicode+1)))
>>> [x for x in unicode_chars if len(x.lower()) == 0]
[]
看起来案例 2 也被破解了。
我们也可以将上述逻辑应用于upper
。对于案例 1,_PyUnicode_ToUpperFull
的实现与其较低的对应部分几乎相同;对于情况 2,相应的列表理解同样是 returns 一个空列表。
结论
不,lower
和 upper
永远不会缩短任何内容。
转换为大写或小写时,字符串可能会变长(根据 Unicode 代码点)。例如,'ß'.upper()
的计算结果为 'SS'
。但是有没有变短的琴弦?也就是说,是否存在一个字符串 s
使得表达式
len(s.lower()) < len(s) or len(s.upper()) < len(s)
计算为 True
?
我认为这可能取决于实现。我会根据 CPython 源码回答。
在我看来,有两种可能的情况,在字符串上调用 lower
可以使其更短。
- 两个相邻的 Unicode 点的某种组合被转换为一个 Unicode 点。
- 单个 Unicode 点被转换为空字符串。
我们可以通过检查内部小写转换函数的类型签名来确定情况 1 是否可能。在 Objects/unicodectype.c.
中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;
}
我不是 100% 理解这段代码,但我观察到第一个参数 ch
是单个 Unicode 点。由于它只对单个字符而不是字符组合进行操作,因此情况 1 似乎已被排除;代码点的组合不会变成更小的序列。
除此之外,我们可以通过迭代到 sys.maxunicode
并查看是否有任何单个值在降低后的长度为零来确定情况 2 是否曾经发生过。
>>> import sys
>>> unicode_chars = list(map(chr, range(sys.maxunicode+1)))
>>> [x for x in unicode_chars if len(x.lower()) == 0]
[]
看起来案例 2 也被破解了。
我们也可以将上述逻辑应用于upper
。对于案例 1,_PyUnicode_ToUpperFull
的实现与其较低的对应部分几乎相同;对于情况 2,相应的列表理解同样是 returns 一个空列表。
结论
不,lower
和 upper
永远不会缩短任何内容。