String.ToLower()
如果所有字符都是小写的,是否返回相同的引用(例如,不分配任何新内存)?
内存分配很便宜,但对数以万计的短字符串进行快速检查更便宜。大多数时候,我正在使用的输入已经是小写的,但如果不是,我想这样做。
我正在使用 C# / .NET 特别是,但我的好奇心扩展到其他语言,所以请随意回答你最喜欢的语言!
注意:字符串是不可变的,但这并不意味着函数总是必须返回一个新的,而是意味着没有任何东西可以改变它们的字符内容。
我希望如此,是的。快速测试同意(但这不是证据):
string a = "abc", b = a.ToLower();
bool areSame = ReferenceEquals(a, b); // false
一般来说,尝试与做你想做的比较器一起工作。例如,如果您想要一个不区分大小写的字典,请使用:
var lookup = new Dictionary<string, int>(
StringComparer.InvariantCultureIgnoreCase);
同样地:
bool ciEqual = string.Equals("abc", "ABC",
StringComparison.InvariantCultureIgnoreCase);
字符串是不可变的。String.ToLower() 将始终返回新实例,从而在每次 ToLower() 调用时生成另一个实例。
Sun 的 String.toLowerCase() 的 Java 实现实际上并不总是分配新的字符串。它检查是否所有字符都是小写的,如果是,则返回原始字符串。
[编辑]
实习无济于事——请参阅对此答案的评论。
如果您使用以下代码,它将不会分配新内存,并且会覆盖原始字符串(这可能是您想要的,也可能不是您想要的)。它需要一个 ascii 字符串。如果您在从您无法控制的函数返回的字符串上调用它,预计会发生奇怪的事情。
public static unsafe void UnsafeToLower(string asciiString)
{
fixed (char* pstr = asciiString)
{
for(char* p = pstr; *p != 0; ++p)
*p = (*p > 0x40) && (*p < 0x5b) ? (char)(*p | 0x60) : (*p);
}
}
它需要的时间大约是 ToLowerInvariant 的 25%,并且避免了内存分配。
如果你在一个紧密的循环中经常说 100,000 或更多的字符串,我只会使用这样的东西。