我该如何进行不区分大小写的字符串比较?

265

如何使下面的行不区分大小写?

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username == (string)drUser["Username"]) != -1);

我今天早些时候得到了一些建议,建议我使用:

x.Username.Equals((string)drUser["Username"], StringComparison.OrdinalIgnoreCase)));

问题是我无法让这个工作起来,我尝试了下面的代码行,它能编译但返回错误的结果,已注册用户显示为未注册,未注册用户显示为已注册。

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username.Equals((string)drUser["Username"], 
                                 StringComparison.OrdinalIgnoreCase)));

有人能指出问题吗?


1
drUser["Enrolled"] 应该是什么数据类型?它看起来像一个布尔值,但 FindIndex() 返回索引。如果该用户的索引为0,则返回0,这可能是false。而实际上它是true。在这种情况下,Exists() 方法可能更好。 - drharris
你确定一个字段中没有格式或额外的空格,而另一个字段中有吗? - joshlrogers
2
我建议使用enrolledUsers.Any()而不是FindIndex(和测试)。 - Marc
9个回答

486

在.NET框架(4及以上版本)中,这不是最佳实践来检查相等性。

String.Compare(x.Username, (string)drUser["Username"], 
                  StringComparison.OrdinalIgnoreCase) == 0

请使用以下内容替代

String.Equals(x.Username, (string)drUser["Username"], 
                   StringComparison.OrdinalIgnoreCase) 

MSDN 推荐:

  • 使用String.Equals方法的重载来测试两个字符串是否相等。
  • 使用String.CompareString.CompareTo方法对字符串进行排序,而不是用来检查相等性。

12
你应该使用string.Compare,而不是String.Compare - Fred
8
@Fred 我同意,但你能说明原因吗? - Gusdor
28
@Fred,我希望你能给出技术原因,而不是仅凭Stylecop的说法。我有所遗漏吗? - Gusdor
13
无论是使用 string.compare 还是 String.Compare,它们的意思是相同的,都是用于比较字符串。另外,string 是 System.String 类的同义词。而 Compare 方法是一个扩展方法。@Fred @Gusdor - Nuri YILMAZ
42
使用string比使用String更好,因为它是语言关键字。 首先,String可能不仅指System.String,而string则不能。 其次,string在C#中几乎可以保证存在,而String技术上是.NET的一部分,而不是C#。 - Dave Cousineau
显示剩余9条评论

41
请使用此内容进行比较:
string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);

16
请注意使用CurrentCultureIgnoreCase和OrdinalIgnoreCase的优缺点。如果您不需要文化比较语义,可以使用序号比较来提高性能。 - ErikE

37

你应该像下面这样使用静态String.Compare函数:

x => String.Compare (x.Username, (string)drUser["Username"],
                     StringComparison.OrdinalIgnoreCase) == 0

7
不,你应该使用String.Equals而不是String.Compare。没有必要计算哪个字符串更大,只需要知道它们是否相等即可。 - ErikE
@ErikE:我想知道,你会推荐在6年后使用哪种方法 :-) - Oleg
4
我不觉得有什么疑问!我相信我会建议在需要平等语义时使用“equality”,在需要比较语义时使用“compare”。这有何难度?“IEquatable”和“IComparable”并不是做相同的事情,你可以有实现其中一个但在其中实现另一个没有意义的类。例如,你可以按时间顺序排序传感器采样,而不需要它们相等(IComparable)。另外,你可以指示物品是否相等(IEquatable),但无法对它们进行排序(例如计算机序列号)。 - ErikE
@ErikE:你不理解我的观点。旧的答案对应着写作时的时间。人们不应该去修改旧的答案。这适用于大多数产品。从性能角度来看,最佳实践或最佳选择可能会在以后多次更改。我认为没有必要讨论任何旧的答案。 - Oleg
28
抱歉,我之前把你的评论当成对我的评论正确性的批评。如果你是在承认你的旧答案可能不是最好的,那太好了!然而,我必须对你关于旧答案的观点持不同意见。提供错误信息的旧答案应该被评论并被投反对票,因为它们仍然在向今天的读者提供信息。 - ErikE

8

其他答案都是完全有效的,但是敲入 StringComparison.OrdinalIgnoreCase 有些费时,并且使用 String.Compare 也是如此。

我编写了一个简单的字符串扩展方法,在其中可以通过布尔值指定比较是否区分大小写,以下是完整的代码片段:

using System;

/// <summary>
/// String helpers.
/// </summary>
public static class StringExtensions
{
    /// <summary>
    /// Compares two strings, set ignoreCase to true to ignore case comparison ('A' == 'a')
    /// </summary>
    public static bool CompareTo(this string strA, string strB, bool ignoreCase)
    {
        return String.Compare(strA, strB, ignoreCase) == 0;
    }
}

在使用字符串扩展之前:

然后整个比较大约减少了10个字符-比较:

String.Compare(testFilename, testToStart,true) != 0

使用字符串扩展后:

testFilename.CompareTo(testToStart, true)

3
我不同意这个命名,compare是软件开发中众所周知的函数,而你已经从根本上改变了它的用途。我认为你应该返回一个像是compare那样的整数值,或者将名称更改为其他内容,例如“IsEqual”。 - Fred

8
您可以(尽管有争议)扩展System.String来提供一个忽略大小写的比较扩展方法:
public static bool CIEquals(this String a, String b) {
    return a.Equals(b, StringComparison.CurrentCultureIgnoreCase);
}

并将其用作如下所示:
x.Username.CIEquals((string)drUser["Username"]);

C#允许您创建扩展方法,这些方法可以作为语法糖在您的项目中使用,非常有用。

这不是答案,我知道这个问题很久以前就已经解决了,我只是想添加这些内容。


7

我想写一个扩展方法用于实现忽略大小写比较

public static class StringExtensions
{
    public static bool? EqualsIgnoreCase(this string strA, string strB)
    {
        return strA?.Equals(strB, StringComparison.CurrentCultureIgnoreCase);
    }
}

3
我认为您会在这个链接中找到更多信息:
使用 String 类的 Compare 静态方法比较两个字符串。比较是否不区分大小写取决于其重载之一的第三个参数。例如:

http://codeidol.com/community/dotnet/controlling-case-sensitivity-when-comparing-two-st/8873/

string lowerCase = "abc";
string upperCase = "AbC";
int caseInsensitiveResult = string.Compare(lowerCase, upperCase,
  StringComparison.CurrentCultureIgnoreCase);
int caseSensitiveResult = string.Compare(lowerCase,
  StringComparison.CurrentCulture);

caseSensitiveResult的值为-1(表示小写字母“小于”大写字母),而caseInsensitiveResult的值为零(表示小写字母“等于”大写字母)。


1

使用StringComparison.CurrentCultureIgnoreCase怎么样?


5
这个答案不够详细,请参考 @ocean4dream 的回答:https://dev59.com/dXA75IYBdhLWcg3wv7_A#13965429。 - Jim G.
@decyclone:它比OrdinalIgnoreCase慢,但在某些情况下可能是相关的。因此我不会给-1。https://dev59.com/qHE85IYBdhLWcg3wgDlI - Csaba Toth
同时,https://dev59.com/33VD5IYBdhLWcg3wJIAK - Csaba Toth

-12

你可以随时使用以下函数: .ToLower(); .ToUpper();

将你的字符串转换后再进行比较...

祝你好运


我认为这不会解决他的问题。同时请注意,这个问题已经超过4年了。 - Vojtěch Dohnal
12
这将创建一个新的字符串,所以我认为这非常低效。因为要创建这个新的字符串,所有字符都将被检查并转换为所需的大小写,然后比较还必须再次检查所有字符。因此,它使用更多的内存和处理能力。 - Air2
7
由于内存分配,这种做法非常不好。 - Thorbjørn Lindeijer
这不仅是不必要的内存分配和低效,而且还未通过土耳其测试 - dmitry
在某些情况下,这可能是一种非常有价值的方法。具体来说,当您计划将字符串与许多其他字符串进行比较时,可能会使用switch()或elseif ladder(例如,在检查您控制的命令列表时,因此知道不会受到I18N小写问题的影响;或者针对一个wordle单词列表)。每次比较都不区分大小写可能不太高效,但更重要的是,它不如str == "a"case "a"或哈希表检查易读。然而,对于手头的问题...是的,最好用正确的方式来做。 - Dewi Morgan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接