在 C# 中比较字符串

Tip

本文是已了解至少一种编程语言并正在学习 C# 的开发人员的 “基础知识 ”部分的一部分。 如果你不熟悉编程,请先 学习入门 教程。

来自另一种语言? 在 C# 中,对字符串使用 == 时比较的是 ,而不是引用,这很像 Java 的 equals 或 JavaScript 的 ===。 关键区别在于,C# 允许你通过 StringComparison 值选择使用 序数(二进制)比较还是 区域性相关比较。

比较字符串以回答以下两个问题之一: 这两个字符串是否相等?这些字符串排序的顺序是什么? C# 允许在回答任一问题时控制两个独立因素:

  • 区分大小写 — 是否将 "Hello""hello" 视为相同。
  • 比较种类序值(比较每个字符的二进制值)或 区域性(应用特定区域的语言规则)。

枚举 StringComparison 将这些因素合并到传递给比较方法的单个值中。

相等性比较

默认情况下,String.Equals 方法和 == 运算符都执行区分大小写且按序号进行的比较。 序号比较检查每个字符的二进制值,因此它很快,并在每台计算机上提供相同的结果。 你可以通过调用接受 StringComparison 值的重载版本来明确表明你的意图:

string root = @"C:\users";
string root2 = @"C:\Users";

// Equals and == both perform a case-sensitive, ordinal comparison.
Console.WriteLine(root.Equals(root2));
// => False
Console.WriteLine(root == root2);
// => False

// Pass a StringComparison value to state the intent explicitly.
Console.WriteLine(root.Equals(root2, StringComparison.Ordinal));
// => False

若要在保留序号语义时忽略大小写,请传递 StringComparison.OrdinalIgnoreCase

string root = @"C:\users";
string root2 = @"C:\Users";

// OrdinalIgnoreCase compares the binary values but ignores case.
bool equalIgnoringCase = string.Equals(root, root2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine(equalIgnoringCase);
// => True

按排序顺序比较

若要确定排序顺序而不是相等,请使用 String.Compare。 它返回负数、零或正数,以指示第一个字符串是在之前、与第二个字符串位于同一位置还是之后进行排序:

string first = "Avocado";
string second = "Banana";

// Compare returns a negative number, zero, or a positive number
// to indicate sort order. Specify the comparison type explicitly.
int order = string.Compare(first, second, StringComparison.Ordinal);
Console.WriteLine(order < 0
    ? $"'{first}' sorts before '{second}'."
    : $"'{first}' sorts at or after '{second}'.");
// => 'Avocado' sorts before 'Banana'.

Important

CompareCompareTo 默认使用 区域性相关 比较,而 Equals== 默认使用 序号 比较。 为了避免意外,请传递显式 StringComparison 值,以便代码指出它想要的行为。

使用模式匹配 isswitch 与常量进行比较

如果与常量进行比较的值是常量,则可以将 is 运算符常量模式 一起使用,作为可读的替代方法 ==

string status = "Ready";

// When the right operand is a constant, the is operator and a
// constant pattern read as an alternative to ==.
if (status is "Ready")
{
    Console.WriteLine("The system is ready.");
}
// => The system is ready.

若要将字符串与多个常量进行比较,请使用 switch 表达式。 每个 arm 都会测试 一个常量模式,丢弃模式 (_) 处理不匹配的每个值。 下一个示例将方向关键字映射到旅行说明:

foreach (string heading in new[] { "North", "South", "East", "West", "NE" })
{
    // A switch expression matches each constant pattern in turn and
    // returns the first match. The discard (_) handles every other value.
    string instruction = heading switch
    {
        "North" => "Travel due North for 10 km.",
        "South" => "Travel due South for 10 km.",
        "East" => "Travel due East for 10 km.",
        "West" => "Travel due West for 10 km.",
        _ => $"Unknown heading: {heading}.",
    };
    Console.WriteLine(instruction);
}
// => Travel due North for 10 km.
// => Travel due South for 10 km.
// => Travel due East for 10 km.
// => Travel due West for 10 km.
// => Unknown heading: NE.

测试字符串常量的 switch 表达式会执行与 == 相同的区分大小写的序号比较,因此 "north""North" 分支不匹配。

选择正确的比较

根据数据选择比较方式,而不是凭习惯:

  • 对于标识符、文件路径、协议令牌和其他计算机定义的文本,请使用 Ordinal (或 OrdinalIgnoreCase 忽略大小写)。 序数比较快速且在不同文化之间保持一致。
  • 对于供用户阅读和排序的文本(例如姓名或产品标题),请使用 CurrentCulture,以便排序顺序符合用户的预期。

区域性比较会使用因区域性而异的语言规则,因此可能产生令人惊讶的结果。 例如,某些区域性设置会将 "ss""ß" 视为相等,并且字符串的排序结果在不同计算机之间可能会有所不同。 由于存在这种可变性,因此仅应将区域性相关的比较用于真正的自然语言文本,并且在对同一集合同时进行排序和搜索时,应使用相同的比较方式。

有关区域性敏感的比较(包括全球化相关注意事项和平台差异)的深入介绍,请参阅在 .NET 中比较字符串的最佳做法

另见