小窍门
本文是已了解至少一种编程语言并正在学习 C# 的开发人员的 “基础知识 ”部分的一部分。 如果你不熟悉编程,请先 学习入门 教程。
来自另一种语言? C# string 方法,如 Contains、StartsWith 和 IndexOf,对应于 Java 的 String 和 JavaScript 的 String.prototype 中的相应方法。 主要区别在于,某些 C# 搜索默认使用 序号比较且区分大小写。 其他则默认采用当前区域性的语义。 对于面向用户的搜索,可能需要传递值 StringComparison 。
该 String 类包括回答两个日常问题的方法:
- 此字符串是否包含该文本? — 使用 Contains、 StartsWith或 EndsWith。
- 该文本出现在哪里? — 使用 IndexOf 或 LastIndexOf。
可以使用正则表达式生成更复杂的搜索和替换算法。 有关正则表达式和其他字符串操作的详细信息,请参阅有关 字符串操作的语言参考文章。
检查字符串是否包含文本
使用 Contains、 StartsWith或 EndsWith 测试子字符串是否存在:
string factMessage = "Extension methods have all the capabilities of regular static methods.";
// Write the string and include the quotation marks.
Console.WriteLine($"\"{factMessage}\"");
// Default comparisons are case sensitive.
bool containsSearchResult = factMessage.Contains("extension");
Console.WriteLine($"""Contains "extension"? {containsSearchResult}""");
// For user-facing searches, pass a StringComparison value to control case and culture.
bool ignoreCaseSearchResult = factMessage.StartsWith("extension", StringComparison.CurrentCultureIgnoreCase);
Console.WriteLine($"""Starts with "extension"? {ignoreCaseSearchResult} (ignoring case)""");
bool endsWithSearchResult = factMessage.EndsWith(".", StringComparison.Ordinal);
Console.WriteLine($"Ends with '.'? {endsWithSearchResult}");
// => "Extension methods have all the capabilities of regular static methods."
// => Contains "extension"? False
// => Starts with "extension"? True (ignoring case)
// => Ends with '.'? True
这些方法默认使用 区分大小写的序号比较。 若要接受用户输入或忽略显示文本大小写,请传递一个 StringComparison 值,例如 StringComparison.CurrentCultureIgnoreCase 或 StringComparison.OrdinalIgnoreCase。
搜索单个字符时,请使用 Contains 的 char 重载。 它避免分配仅包含一个字符的字符串,而且更直接:
string path = "/usr/local/bin";
bool hasSlash = path.Contains('/');
Console.WriteLine($"Path contains '/': {hasSlash}");
// => Path contains '/': True
找到文本的位置
IndexOf 返回子字符串(或字符)第一个匹配项的从零开始的索引,并 LastIndexOf 返回最后一个匹配项的索引。 当搜索文本不存在时,两者都返回 -1 。 将它们组合起来,以提取两个标记之间的文本:
string factMessage = "Extension methods have all the capabilities of regular static methods.";
Console.WriteLine($"\"{factMessage}\"");
// Extract the text between the first and last occurrence of "methods".
int first = factMessage.IndexOf("methods") + "methods".Length;
int last = factMessage.LastIndexOf("methods");
string between = factMessage.Substring(first, last - first);
Console.WriteLine($"""Substring between "methods" and "methods": '{between}'""");
// => "Extension methods have all the capabilities of regular static methods."
// => Substring between "methods" and "methods": ' have all the capabilities of regular static '
如果你需要的是所有匹配项,而不是第一个或最后一个,可以将前一次结果加 1 作为 startIndex 参数传入来重复查找,或者改用正则表达式。
选择正确的比较
大多数搜索重载都接受可选 StringComparison 值。 根据要搜索的数据类型选取它:
- 如果要搜索标识符、文件路径、协议令牌或其他任何计算机定义的内容,请使用 Ordinal。
- 如果要搜索相同类型的计算机定义数据,但希望不区分大小写,请使用 OrdinalIgnoreCase。
- 如果你要搜索需要应用当前区域设置规则的用户可见文本,请使用 CurrentCulture。
- 如果要搜索相同的用户可见文本并想要忽略大小写,请使用 CurrentCultureIgnoreCase。
- 如果要搜索必须在每个计算机和区域性上比较相同的持久化数据,请使用 InvariantCulture (很少需要)。
序号比较是最快的选项,对于任何非自然语言文本,它都是合适的默认选择。 区域性比较的速度要慢得多,而且可能产生意外结果。 例如,在某些文化中,小写 i 与大写 I 不匹配。仅将其用于用户针对普通文本执行的搜索。
有关考虑区域性差异的比较的深入介绍,请参阅 比较字符串的最佳做法。