大写与小写


85

在进行不区分大小写的比较时,将字符串转换为大写还是小写更有效?有关系吗

在这篇SO文章中建议使用ToUpper来提高C#的效率,因为“ Microsoft以这种方式进行了优化”。但是我也读过这样的论点,即转换ToLower与ToUpper取决于您的字符串包含更多内容,并且通常字符串包含更多小写字符,这使ToLower更加高效。

我特别想知道:

  • 有没有一种方法可以优化ToUpper或ToLower,使其比另一种更快?
  • 在大写或小写字符串之间进行不区分大小写的比较会更快吗?为什么?
  • 是否存在任何编程环境(例如C,C#,Python等),其中一种情况明显优于另一种情况,为什么?

Answers:


90

转换为大写或小写以进行不区分大小写的比较是不正确的,因为某些文化(尤其是土耳其)具有“有趣的”特征。而是使用StringComparer用适当的选项。

MSDN在字符串处理方面有一些很棒的准则。您可能还需要检查您的代码是否通过了Turkey测试

编辑:注意Neil对序数不区分大小写的比较的评论。这整个境界很阴暗:(


15
是的,StringComparer很不错,但是问题没有得到解决……在无法使用StringComparer的情况下,例如对字符串的swtich语句;我应该在交换机中进行ToUpper还是ToLower?
joshperry

7
使用StringComparer和“ if” /“ else”代替使用ToUpper或ToLower。
乔恩·斯基特

5
约翰,我知道转换成小写是不正确的,但是我没有听说转换成大写是不正确的。您可以提供示例还是参考?您链接到的MSDN文章说:“从行为上讲,使用OrdinalIgnoreCase进行的比较是两个调用的组合:对两个字符串参数调用ToUpperInvariant,然后进行顺序比较。” 在标题为“序数字符串操作”的部分中,它将在代码中重述此内容。
尼尔

2
@Neil:有趣,我没看过。对于不区分大小写的顺序比较,我想这很公平。毕竟,必须选择一些东西。对于不区分文化的区分大小写的比较,我认为仍然存在一些奇怪行为的余地。会在答案中指出您的意见...
Jon Skeet

4
@Triynko:我认为重要的是主要集中在正确性上,以使快速获得错误答案通常比缓慢获得错误答案更好(有时更糟)。
乔恩·斯基特

25

Microsoft在MSDN上:

在.NET Framework中使用字符串的最佳实践

有关字符串用法的建议

为什么?来自微软

将字符串规范化为大写

一小部分字符转换为小写字母后就无法往返。

不能往返的这种角色的例子是什么?

  • 开始:希腊Rho符号(U + 03f1)ϱ
  • 大写:字母 Capital Greek Rho(U + 03a1)Ρ
  • 小写:小希腊Rho(U + 03c1)ρ

ϱ, Ρρ

.NET小提琴

Original: ϱ
ToUpper: Ρ
ToLower: ρ

这就是为什么,如果要进行不区分大小写的比较,则会将字符串转换为大写而不是小写。

因此,如果必须选择一个,请选择大写


原因是什么?
2013年

@bjan原因是因为这样做很不好。
伊恩·博伊德

1
什么字符组?往返甚至意味着什么?
johv 2014年

1
@johv从链接:“往返意味着将字符从一个语言环境转换为另一种代表字符数据的语言环境,然后从转换后的字符中准确检索原始字符。” 什么字符组?我不知道,但是我将猜测i土耳其语中的小写字母何时变为İ,而不是I您惯用的那个。另外,我们习惯于大写I成为i,但在土耳其变成ı
伊恩·博伊德

3
回到答案原来的问题:对于一种大写变体,有些语言知道一种以上的小写变体。除非您知道何时使用哪种表示形式的规则(希腊文的另一个示例:小西格玛字母,否则请在单词开头或中间使用σ,在单词结尾使用ς(请参见en.wikipedia.org/wiki/Sigma),你不能安全地转换回小写变型。
阿空加瓜

19

根据MSDN,传递字符串并告诉比较忽略大小写效率更高:

String.Compare(strA,strB,StringComparison.OrdinalIgnoreCase)等效于(但比)调用

String.Compare(ToUpperInvariant(strA),ToUpperInvariant(strB),StringComparison.Ordinal)。

这些比较仍然非常快。

当然,如果您要一遍又一遍地比较一个字符串,那么这可能不成立。


12

基于倾向于具有更多小写字母条目的字符串,ToLower理论上应该更快(很多比较,但分配很少)。

在C语言中,或使用每个字符串的可单独访问的元素(例如C字符串或C ++中的STL的字符串类型)时,它实际上是字节比较-因此比较UPPERlower

如果您偷偷摸摸地将琴弦装入 long数组中,则可以对整个字符串进行非常快速的比较,因为它一次可以比较4个字节。但是,加载时间可能不值得。

为什么您需要知道哪个更快?除非您进行度量标准比较,否则运行几个周期的速度与整体执行的速度无关,听起来像是过早的优化:)


11
要回答为什么我需要知道哪个更快的问题:我不需要知道,我只想知道。:)这只是看到有人提出要求(例如“比较大写字符串更快!”)并想知道它是否真的是真实的和/或为什么他们提出该要求的情况。
帕拉帕

1
这是有道理的-我也一直对这样的事情感到好奇:)
沃伦

对于C字符串,要转换s并转换t为long类型的数组,以使字符串相等(如果数组相等),则必须向下走s和t直到找到终止'\0'字符(否则您可能会比较字符串末尾的垃圾,这可能是调用未定义行为的非法内存访问)。但是,为什么不在逐个浏览字符时进行比较呢?使用C ++字符串,您可能可以得到length和.c_str(),转换为along *并比较length的前缀.size() - .size()%(sizeof long)。对我来说看起来有点可疑。
JonasKölker'17

6

微软已经优化了ToUpperInvariant(),没有ToUpper()。区别在于不变式对文化更友好。如果需要对可能因区域而异的字符串进行不区分大小写的比较,请使用Invariant,否则不变转换的性能无关紧要。

我不能说ToUpper()还是ToLower()更快。我从未尝试过它,因为我从来没有遇到过如此重要的情况。


如果Microsoft已优化用于执行大写比较的代码,是否是因为大写字母的ASCII码只有两位数字65-90,而ASCII码小写字母97-122却包含3位数字(需要更多处理)?
Medo Medo

3
@Medo我不记得进行优化的确切原因,但是2位数和3位数几乎不是原因,因为所有字母都存储为二进制数,因此十进制数字基于它们的存储方式实际上没有含义。
丹·赫伯特

4

如果在C#中进行字符串比较,则使用.Equals()的速度要快得多,而不是将两个字符串都转换为大写或小写。使用.Equals()的另一个大优点是没有为2个新的大写/小写字符串分配更多的内存。


4
另外,如果您选择正确的选项,它实际上会给您正确的结果:)
Jon Skeet

1

真的没关系。对于ASCII字符,这绝对没有关系-只需进行几次比较,就可以任意方向翻转。Unicode可能要复杂一些,因为有些字符会以奇怪的方式更改大小写,但是除非您的文本中充满了这些特殊字符,否则Unicode确实应该没有任何区别。


1

正确执行此操作后,如果转换为小写字母,应该会获得很小的微不足道的速度优势,但是正如许多人所暗示的那样,这是与文化相关的,并且不是在函数中继承而是在转换的字符串中继承(很多小写字母)意味着对内存的分配很少)-如果您的字符串包含很多大写字母,则转换为大写字母的速度更快。


0

这取决于。如上所述,仅纯ASCII,其相同。在.NET中,阅读并使用String.Compare正确的i18n东西(语言文化和unicode)。如果您知道有关输入可能性的任何信息,请使用更常见的情况。

请记住,如果您要进行多个字符串比较,则长度是一个很好的第一判别器。


-2

如果您使用的是纯ASCII,则没关系。这只是OR x,32与AND x,224。Unicode,我不知道...


4
这是完全错误的-与32进行或运算仅适用于AZ和字符64-127;它弄乱了所有其他字符。与32进行AND运算甚至更加错误-结果将始终为0(空)或32(空格)。
亚当·罗森菲尔德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.