C 语言中字符串比较方法的差异#

Differences in string compare methods in C#

提问人:Craig 提问时间:9/5/2008 最后编辑:AGuyCalledGeraldCraig 更新时间:4/23/2018 访问量:207845

问:

在 C# 中比较字符串非常简单。事实上,有几种方法可以做到这一点。我在下面的块中列出了一些。我很好奇的是它们之间的区别,以及什么时候应该使用一个而不是其他?是否应该不惜一切代价避免这种情况?还有更多我没有列出的吗?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(注意:我在这个例子中寻找相等,不小于或大于,但也可以随时对此发表评论)

C# 字符串 比较

评论

5赞 johnc 1/8/2009
一个陷阱是你不能做 stringValue.Equals(null),因为这假设你可以在 null 上调用一个方法
1赞 Robert Harvey 5/6/2014
MSDN 参考
1赞 Syaiful Nizam Yahya 12/12/2019
@RobertHarvey 我来 stackoverflow 的原因是为了让我不必阅读多页来获得答案。
0赞 Robert Harvey 12/12/2019
@Syaiful:我来 Stack Overflow 的原因是为了找到文档中没有的答案。

答:

76赞 Ed S. 9/5/2008 #1

来自 MSDN:

“CompareTo 方法主要用于排序或 按字母顺序排列操作。当主要 方法调用的用途是确定两个字符串是否 等效。要确定两个字符串是否等效,请调用 Equals 方法。

他们建议在仅仅寻求平等时使用而不是使用。我不确定班级之间和班级之间是否有区别。我有时会用 或 代替我自己的类,以防以后有人出现并重新定义该类的运算符。.Equals.CompareTo.Equals==string.EqualsObject.ReferenceEquals====

评论

22赞 juan 2/5/2009
你有没有遇到过这种情况?(重新定义 == )...我认为它太防御性编程了=)
0赞 Ed S. 2/5/2009
是的,这就是为什么我现在在寻找对象相等:)时使用 Object.ReferenceEquals 的原因。这可能有点过度防御,但我对此并不疯狂,说实话,这种情况并不经常出现。
0赞 Dave Van den Eynde 2/27/2012
我怀疑这种“防御性编码”是否有用。如果类所有者需要重写 == 运算符,然后发现没有人在使用它怎么办?
1赞 Ed S. 2/28/2012
@DaveVandenEynde:是的......我不久前写过这个。我不经常这样做,只是覆盖.适当时相等。
1赞 JJS 2/27/2013
Microsoft 的建议记录在这里:在 .NET Framework 中使用字符串的最佳做法
5赞 OwenP 9/5/2008 #2

在你在这里列出的表格中,两者之间没有太大区别。 最终调用一个使用当前区域性进行比较的方法; 由操作员调用。CompareToCompareInfoEquals==

如果你考虑过载,那么事情就会变得不同。 并且只能使用当前区域性来比较字符串。 并且可以采用一个枚举参数,该参数允许您指定不区分区域性或不区分大小写的比较。仅允许您指定和使用默认区域性以外的区域性执行比较。Compare==EqualsString.CompareStringComparisonString.CompareCultureInfo

由于它的多功能性,我发现我使用的比任何其他比较方法都多;它让我可以准确地指定我想要什么。String.Compare

-1赞 hometoast 9/5/2008 #3

用。Equals 也更容易阅读

7赞 viggity 9/5/2008 #4

并不是说性能通常很重要,因为 99% 的时间你需要这样做,但是如果你不得不在数百万次的循环中执行此操作,我强烈建议你使用 .等于或 ==,因为一旦它找到一个不匹配的字符,它就会将整个内容抛出为 false,但如果您使用 CompareTo,它将不得不找出哪个字符小于另一个字符,从而导致性能时间稍差。

如果你的应用将在不同的国家/地区运行,我建议你看看 CultureInfo 的含义,并可能使用 .等于。由于我只真正为美国编写应用程序(并且不在乎它是否不能由某人正常工作),因此我总是只使用 ==。

242赞 Lasse V. Karlsen 9/5/2008 #5

Here are the rules for how these functions work:

stringValue.CompareTo(otherStringValue)

  1. null comes before a string
  2. it uses , which means it will use a culture-dependent comparison. This might mean that will compare equal to in Germany, or similarCultureInfo.CurrentCulture.CompareInfo.CompareßSS

stringValue.Equals(otherStringValue)

  1. null is not considered equal to anything
  2. unless you specify a option, it will use what looks like a direct ordinal equality check, i.e. is not the same as , in any language or cultureStringComparisonßSS

stringValue == otherStringValue

  1. Is not the same as .stringValue.Equals()
  2. The operator calls the static method (which in turn goes to an internal to do the comparison.==Equals(string a, string b)EqualsHelper
  3. Calling on a string gets reference exception, while on does not..Equals()nullnull==

Object.ReferenceEquals(stringValue, otherStringValue)

Just checks that references are the same, i.e. it isn't just two strings with the same contents, you're comparing a string object with itself.


Note that with the options above that use method calls, there are overloads with more options to specify how to compare.

My advice if you just want to check for equality is to make up your mind whether you want to use a culture-dependent comparison or not, and then use or , depending on the choice..CompareTo.Equals

评论

6赞 Kevin 2/5/2009
"stringValue.Equals(otherStringValue): null is not equal to null" Lol, I'd say not. null equals ObjectReferenceNotSet exception.
32赞 Dan C. 2/5/2009
== is not the same as .Equals()... The == operator calls the static Equals(string a, string b) method (which in turn goes to an internal EqualsHelper to do the comparison. Calling .Equals on a null string gets null reference exc., while on == does not.
2赞 Dan C. 2/5/2009
On the other hand, .Equals is slightly faster (one less method call internally), but less readable - arguably, of course :).
0赞 amesh 8/9/2012
I was thinking '==' will do reference comparisons and object.equals will do value comparisons.How '==' and string.equals work as the same?
0赞 Joe Cartano 10/30/2013
the == difference should be called out in the answer, that is a pretty big difference.
50赞 max 2/5/2009 #6

If you are ever curious about differences in BCL methods, Reflector is your friend :-)

I follow these guidelines:

Exact match: EDIT: I previously always used == operator on the principle that inside Equals(string, string) the object == operator is used to compare the object references but it seems strA.Equals(strB) is still 1-11% faster overall than string.Equals(strA, strB), strA == strB, and string.CompareOrdinal(strA, strB). I loop tested with a StopWatch on both interned/non-interned string values, with same/different string lengths, and varying sizes (1B to 5MB).

strA.Equals(strB)

Human-readable match (Western cultures, case-insensitive):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

Human-readable match (All other cultures, insensitive case/accent/kana/etc defined by CultureInfo):

string.Compare(strA, strB, myCultureInfo) == 0

Human-readable match with custom rules (All other cultures):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0
20赞 Jonathan C Dickinson 2/5/2009 #7

正如 Ed 所说,CompareTo 用于排序。

但是,两者之间是有区别的。等于 和 ==。

== 解析为以下代码:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

原因很简单,以下内容将引发异常:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

以下不会:

string a = null;
string b = "foo";

bool equal = a == b;

评论

0赞 serge 5/28/2021
区分大小写呢?
0赞 serge 5/28/2021
和备注你可以使用string.Equals(a, b)
-9赞 David 3/25/2010 #8

跟。等于,您还将获得 StringComparison 选项。非常方便忽略案例和其他事情。

顺便说一句,这将计算为 false

string a = "myString";
string b = "myString";

return a==b

由于 == 比较 a 和 b(指针)的值,因此仅当指针指向内存中的同一对象时,其计算结果为 true。.Equals 取消引用指针并比较指针中存储的值。 a.Equals(b) 在这里为真。

如果将 b 更改为:

b = "MYSTRING";

则 a.Equals(b) 为 false,但

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

是真的

a.CompareTo(b) 调用字符串的 CompareTo 函数,该函数比较指针处的值,如果存储在 a 处的值小于存储在 b 处的值,则返回 <0,如果 a.Equals(b) 为 true,则返回 0,否则返回 >0。但是,这是区分大小写的,我认为 CompareTo 可能有一些选项可以忽略大小写等,但现在没有时间查看。 正如其他人已经说过的那样,这将用于排序。以这种方式比较平等将导致不必要的开销。

我确定我遗漏了一些东西,但我认为如果您需要更多详细信息,这应该足以开始实验。

评论

9赞 Goyuix 4/2/2010
a==b 部分不正确。对于 String 类,== 运算符实际上是重载的,它比较值,而不考虑实际引用。
15赞 Ryszard Dżegan 3/7/2013 #9

有关字符串比较问题的良好解释和做法,请参阅在 Microsoft .NET 2.0 中使用字符串的新建议一文,以及在 .NET Framework 中使用字符串的最佳做法


提到的每种方法(和其他方法)都有特定的用途。它们之间的主要区别在于它们默认使用的 StringComparison 枚举类型。有几种选择:

  • 当前文化
  • CurrentCultureIgnoreCase
  • InvariantCulture (不变文化)
  • InvariantCultureIgnoreCase
  • 序数
  • OrdinalIgnoreCase

上述每种比较类型都针对不同的用例:

  • 序数
    • 区分大小写的内部标识符
    • XML 和 HTTP 等标准中区分大小写的标识符
    • 区分大小写的安全相关设置
  • OrdinalIgnoreCase
    • 不区分大小写的内部标识符
    • XML 和 HTTP 等标准中不区分大小写的标识符
    • 文件路径(在 Microsoft Windows 上)
    • 注册表项/值
    • 环境变量
    • 资源标识符(例如句柄名称)
    • 不区分大小写的安全性相关设置
  • InvariantCulture 或 InvariantCultureIgnoreCase
    • 一些人保留了与语言相关的数据
    • 显示需要固定排序顺序的语言数据
  • CurrentCulture 或 CurrentCultureIgnoreCase
    • 向用户显示的数据
    • 大多数用户输入

请注意,自 .NET 2.0 以来,StringComparison 枚举以及字符串比较方法的重载就存在。


String.CompareTo 方法 (String)

实际上是 IComparable.CompareTo 方法的类型安全实现。默认解释:CurrentCulture。

用法:

CompareTo 方法主要用于排序或按字母顺序排列操作

因此

Implementing the IComparable interface will necessarily use this method

String.Compare Method

A static member of String Class which has many overloads. Default interpretation: CurrentCulture.

Whenever possible, you should call an overload of the Compare method that includes a StringComparison parameter.

String.Equals 方法

从 Object 类中重写并重载以实现类型安全。默认解释:序数。 请注意:

String 类的相等方法包括静态 Equals、静态运算符 ==实例方法 Equals


StringComparer 类

还有另一种处理字符串比较的方法,特别是针对排序:

可以使用 StringComparer 类创建特定于类型的比较,以对泛型集合中的元素进行排序。Hashtable、Dictionary、SortedList 和 SortedList 等类使用 StringComparer 类进行排序。

评论

2赞 supercat 3/4/2014
根据 SO 上的其他一些帖子,除了序数方法之外,所有方法都有 Compare(a,b) 和 Compare(b,a) 都可以返回 1 的情况,并且该错误已被归类为“不会修复”。因此,我不确定任何此类比较是否有任何用例。
0赞 Noctis 11/4/2014
@supercat你能链接到那个,或者举个例子吗?
1赞 supercat 11/4/2014
有关该问题的讨论,请参阅 stackoverflow.com/questions/17599084/...
2赞 Rauld 6/28/2013 #10

需要注意的一个很大区别是。如果第一个字符串为 null,Equals() 将抛出异常,而 == 不会。

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");
1赞 John DiFini 12/15/2017 #11
  • S1 中。CompareTo(s2):如果主要目的是确定两个字符串是否等效,则不要使用
  • s1 == s2:不能忽略大小写
  • S1 中。Equals(s2, StringComparison):如果 s1 为 null,则引发 NullReferenceException
  • String.Equals(s2, StringComparison):通过消除过程,这个静态方法是 WINNER(假设一个典型的用例来确定两个字符串是否等效)!