提问人:Boris Callens 提问时间:1/15/2009 最后编辑:Uwe KeimBoris Callens 更新时间:6/20/2023 访问量:1210929
不区分大小写的“Contains(string)”
Case insensitive 'Contains(string)'
问:
有没有办法使以下返回为真?
string title = "ASTRINGTOTEST";
title.Contains("string");
似乎没有允许我设置区分大小写的重载。目前我把它们都大写,但这很愚蠢(我指的是上下大小写的 i18n 问题)。
更新
这个问题由来已久,从那时起,我意识到,如果你愿意全面调查它,我要求对一个非常庞大而困难的话题有一个简单的答案。
在大多数情况下,在单语英语代码库中,这个答案就足够了。我怀疑,因为大多数来这里的人都属于这一类,这是最受欢迎的答案。
然而,这个答案带来了一个固有的问题,即在我们知道两个文本是相同的文化并且我们知道这种文化是什么之前,我们无法比较不区分大小写的文本。这可能是一个不太受欢迎的答案,但我认为它更正确,这就是我这样标记它的原因。
答:
您始终可以先将字符串放大或缩小。
string title = "string":
title.ToUpper().Contains("STRING") // returns true
哎呀,刚刚看到了最后一点。无论如何,不区分大小写的比较可能会做同样的事情,如果性能不是问题,我认为创建大写副本并比较这些副本没有问题。我可以发誓,我曾经看过一次不区分大小写的比较......*
*
评论
可以使用 String.IndexOf 方法并将 StringComparison.OrdinalIgnoreCase
作为要使用的搜索类型:
string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;
更好的是为字符串定义一个新的扩展方法:
public static class StringExtensions
{
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
return source?.IndexOf(toCheck, comp) >= 0;
}
}
请注意,自 C# 6.0 (VS 2015) 起,null 传播可用,对于旧版本使用?.
if (source == null) return false;
return source.IndexOf(toCheck, comp) >= 0;
用法:
string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
评论
paragraph.ToLower(culture).Contains(word.ToLower(culture))
CultureInfo.InvariantCulture
ToLower
string
IEnumerable<char>
string.IndexOf(string)
string.Contains(string)
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string self = "Waldstrasse"; string value = "straße"; Console.WriteLine(self.Contains(value));/* False */ Console.WriteLine(self.IndexOf(value) >= 0);/* True */
你可以像这样使用:IndexOf()
string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.OrdinalIgnoreCase) != -1)
{
// The string exists in the original
}
由于 0(零)可以是索引,因此您可以针对 -1 进行检查。
如果找到该字符串,则从当前实例的开头开始的 value 参数的从零开始的索引位置,如果未找到该字符串,则为 -1。如果 value 为 Empty,则返回值为 startIndex。
使用正则表达式的替代解决方案:
bool contains = Regex.IsMatch("StRiNG to search", Regex.Escape("string"), RegexOptions.IgnoreCase);
评论
RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant;
"."
"This is a sample string that doesn't contain the search string"
"(invalid"
Regex.Escape
IndexOf
Contains
StringExtension 类是前进的方向,我结合上面的几篇文章给出了一个完整的代码示例:
public static class StringExtensions
{
/// <summary>
/// Allows case insensitive checks
/// </summary>
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
return source.IndexOf(toCheck, comp) >= 0;
}
}
评论
StringComparison
答案的一个问题是,如果字符串为 null,它将引发异常。您可以将其添加为检查,这样它就不会:
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
if (string.IsNullOrEmpty(toCheck) || string.IsNullOrEmpty(source))
return true;
return source.IndexOf(toCheck, comp) >= 0;
}
评论
if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck);
使用这个:
string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);
评论
Contains
Compare
Contains
IndexOf
我知道这不是 C#,但在框架 (VB.NET) 中已经有这样的函数
Dim str As String = "UPPERlower"
Dim b As Boolean = InStr(str, "UpperLower")
C# 变体:
string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");
这既干净又简单。
Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)
评论
fileNamestr
*
+
.
Contains
fileNamestr
Regex.Escape(fileNamestr)
测试字符串是否包含字符串(感谢@QuarterMeister)paragraph
word
culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0
其中 是描述
编写文本所用语言的 CultureInfo 实例。culture
此解决方案对不区分大小写的定义是透明的,这与语言有关。例如,英语使用字符和第九个字母的大小写版本,而土耳其语则将这些字符用于其 29 个字母长的字母表中的第 11 个和第 12 个字母。土耳其语大写字母“i”是陌生的字符“İ”。I
i
因此,字符串 和 在英语中是同一个词,但在土耳其语中是不同的词。据我了解,一个是“精神”的意思,另一个是拟声词。(土耳其人,如果我错了,请纠正我,或者提出一个更好的例子)tin
TIN
总而言之,如果您知道文本使用的语言,您只能回答“这两个字符串是否相同但在不同情况下”的问题。如果你不知道,你将不得不下注。鉴于英语在软件领域的霸权地位,您可能应该求助于 CultureInfo.InvariantCulture
,因为它以熟悉的方式是错误的。
评论
culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0
使用正则表达式是实现此目的的直接方法:
Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
评论
如果您担心国际化(或者可以重新实现它),则 VisualBasic 程序集中的方法是最佳方法。从dotNeetPeek中可以看出,它不仅考虑了大写字母和小写字母,还考虑了假名类型和全角与半角字符(主要与亚洲语言有关,尽管罗马字母也有全角版本)。我跳过了一些细节,但请查看私有方法:InStr
InternalInStrText
private static int InternalInStrText(int lStartPos, string sSrc, string sFind)
{
int num = sSrc == null ? 0 : sSrc.Length;
if (lStartPos > num || num == 0)
return -1;
if (sFind == null || sFind.Length == 0)
return lStartPos;
else
return Utils.GetCultureInfo().CompareInfo.IndexOf(sSrc, sFind, lStartPos, CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth);
}
OrdinalIgnoreCase、CurrentCultureIgnoreCase 还是 InvariantCultureIgnoreCase?
由于缺少此功能,因此以下是有关何时使用哪一个的建议:
做
- 用于比较
作为与区域性无关的字符串匹配的安全默认值。
StringComparison.OrdinalIgnoreCase
- 使用比较
以提高速度。
StringComparison.OrdinalIgnoreCase
- 使用字符串操作
向用户显示输出时。
StringComparison.CurrentCulture-based
- 根据不变性切换字符串操作的当前使用情况
文化,使用非语言或当比较在
语言上无关紧要时(例如,符号)。StringComparison.Ordinal
StringComparison.OrdinalIgnoreCase
- 使用而不是何时使用
规范化字符串以进行比较。
ToUpperInvariant
ToLowerInvariant
注意 事项
- 对未显式执行的字符串操作使用重载 或隐式指定字符串比较机制。
- 在大多数情况下使用基于字符串
的操作;为数不多的例外之一是
保留具有语言意义但与文化无关的数据。StringComparison.InvariantCulture
根据这些规则,您应该使用:
string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.[YourDecision]) != -1)
{
// The string exists in the original
}
而 [YourDecision] 取决于上面的建议。
来源链接:http://msdn.microsoft.com/en-us/library/ms973919.aspx
评论
就像这样:
string s="AbcdEf";
if(s.ToLower().Contains("def"))
{
Console.WriteLine("yes");
}
评论
这与此处的其他示例非常相似,但我决定将枚举简化为 bool,因为通常不需要其他替代方法。这是我的例子:
public static class StringExtensions
{
public static bool Contains(this string source, string toCheck, bool bCaseInsensitive )
{
return source.IndexOf(toCheck, bCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0;
}
}
用法是这样的:
if( "main String substring".Contains("SUBSTRING", true) )
....
这里的诀窍是查找字符串,忽略大小写,但保持完全相同(大小写相同)。
var s="Factory Reset";
var txt="reset";
int first = s.IndexOf(txt, StringComparison.InvariantCultureIgnoreCase) + txt.Length;
var subString = s.Substring(first - txt.Length, txt.Length);
输出为“Reset”
if ("strcmpstring1".IndexOf(Convert.ToString("strcmpstring2"), StringComparison.CurrentCultureIgnoreCase) >= 0){return true;}else{return false;}
您可以使用函数。这将不区分大小写string.indexof ()
新手的简单方法:
title.ToLower().Contains("string");//of course "string" is lowercase.
评论
public static class StringExtension
{
#region Public Methods
public static bool ExContains(this string fullText, string value)
{
return ExIndexOf(fullText, value) > -1;
}
public static bool ExEquals(this string text, string textToCompare)
{
return text.Equals(textToCompare, StringComparison.OrdinalIgnoreCase);
}
public static bool ExHasAllEquals(this string text, params string[] textArgs)
{
for (int index = 0; index < textArgs.Length; index++)
if (ExEquals(text, textArgs[index]) == false) return false;
return true;
}
public static bool ExHasEquals(this string text, params string[] textArgs)
{
for (int index = 0; index < textArgs.Length; index++)
if (ExEquals(text, textArgs[index])) return true;
return false;
}
public static bool ExHasNoEquals(this string text, params string[] textArgs)
{
return ExHasEquals(text, textArgs) == false;
}
public static bool ExHasNotAllEquals(this string text, params string[] textArgs)
{
for (int index = 0; index < textArgs.Length; index++)
if (ExEquals(text, textArgs[index])) return false;
return true;
}
/// <summary>
/// Reports the zero-based index of the first occurrence of the specified string
/// in the current System.String object using StringComparison.InvariantCultureIgnoreCase.
/// A parameter specifies the type of search to use for the specified string.
/// </summary>
/// <param name="fullText">
/// The string to search inside.
/// </param>
/// <param name="value">
/// The string to seek.
/// </param>
/// <returns>
/// The index position of the value parameter if that string is found, or -1 if it
/// is not. If value is System.String.Empty, the return value is 0.
/// </returns>
/// <exception cref="ArgumentNullException">
/// fullText or value is null.
/// </exception>
public static int ExIndexOf(this string fullText, string value)
{
return fullText.IndexOf(value, StringComparison.OrdinalIgnoreCase);
}
public static bool ExNotEquals(this string text, string textToCompare)
{
return ExEquals(text, textToCompare) == false;
}
#endregion Public Methods
}
如果你想检查你传递的字符串是否在字符串中,那么有一个简单的方法。
string yourStringForCheck= "abc";
string stringInWhichWeCheck= "Test abc abc";
bool isContained = stringInWhichWeCheck.ToLower().IndexOf(yourStringForCheck.ToLower()) > -1;
如果字符串是否包含,则此布尔值将返回
这些是最简单的解决方案。
按索引
string title = "STRING"; if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1) { // contains }
通过改变大小写
string title = "STRING"; bool contains = title.ToLower().Contains("string")
由 Regex 提供
Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
.NET Core 2.0+(包括 .NET 5.0+).NET Core 2.0+ (including .NET 5.0+)
自2.0版以来,.NET Core已经有一对方法来处理这个问题:
- String.Contains(Char, StringComparison)
- String.Contains(String, String比较)
例:
"Test".Contains("test", System.StringComparison.CurrentCultureIgnoreCase);
它现在是 .NET Standard 2.1 的正式组成部分,因此是实现此标准版本(或更高版本)的基类库的所有实现的一部分。
评论
为了构建这里的答案,您可以创建一个字符串扩展方法,使其更加用户友好:
public static bool ContainsIgnoreCase(this string paragraph, string word)
{
return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
}
评论
return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
简单而有效
title.ToLower().Contains("String".ToLower())
评论
与前面的答案类似(使用扩展方法),但有两个简单的 null 检查(C# 6.0 及更高版本):
public static bool ContainsIgnoreCase(this string source, string substring)
{
return source?.IndexOf(substring ?? "", StringComparison.OrdinalIgnoreCase) >= 0;
}
如果 source 为 null,则返回 false(通过 null-propagation 运算符?.)
如果 substring 为 null,则视为空字符串并返回 true(通过 null-coalescing 运算符??)
如果需要,StringComparison 当然可以作为参数发送。
根据现有的答案和 Contains 方法的文档,我建议创建以下扩展,该扩展也处理极端情况:
public static class VStringExtensions
{
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
if (toCheck == null)
{
throw new ArgumentNullException(nameof(toCheck));
}
if (source.Equals(string.Empty))
{
return false;
}
if (toCheck.Equals(string.Empty))
{
return true;
}
return source.IndexOf(toCheck, comp) >= 0;
}
}
可以使用字符串比较参数(可从 .NET Core 2.1 及更高版本获得)String.Contains 方法。
public bool Contains (string value, StringComparison comparisonType);
例:
string title = "ASTRINGTOTEST";
title.Contains("string", StringComparison.InvariantCultureIgnoreCase);
评论
最受好评的几个答案都以自己的方式很好和正确,我写在这里是为了添加更多信息、背景和观点。
为了清楚起见,如果 A 中有任何等于 B 的代码点子序列,我们假设字符串 A 包含字符串 B。如果我们接受这一点,问题就简化为两个字符串是否相等的问题。
几十年来,人们一直在详细考虑字符串何时相等的问题。当前的大部分知识状态都封装在 SQL 排序规则中。Unicode 普通形式接近于此的适当子集。但是,除了 SQL 排序规则之外,还有更多内容。
例如,在 SQL 排序规则中,您可以
严格区分二进制 - 因此不同的 Unicode 规范化形式(例如预组合或组合重音)会以不同的方式进行比较。
例如,可以表示为(预组合)或(e与组合急性重音)。
é
U+00e9
U+0065 U+0301
这些是相同还是不同?
Unicode 规范化 - 在这种情况下,上述示例将彼此相等,但不等于 或 。
É
e
口音不敏感,(例如西班牙语、德语、瑞典语等文本)。在这种情况下
U+0065
=U+0065 U+0301
=U+00e9
=é
=e
不区分大小写和重音,因此(例如西班牙语、德语、瑞典语等文本)。在这种情况下
U+00e9
=U+0065 U+0301
=U+00c9
=U+0045 U+0301
=U+0049
=U+0065
=E
=e
=É
=é
Kanatype 敏感或不敏感,即您可以将日本平假名和片假名视为等效或不同。这两个音节包含相同数量的字符,以(大部分)相同的方式组织和发音,但书写方式不同,用途不同。例如,片假名用于外来词或外来名,但平假名用于儿童读物、发音指南(例如红宝石)以及单词没有汉字的地方(或者作者可能不知道汉字,或者认为读者可能不知道)。
全角或半角敏感 - 由于历史原因,日语编码包括某些字符的两种表示形式 - 它们以不同的大小显示。
连字被认为等效与否:见 https://en.wikipedia.org/wiki/Ligature_(写作)
是一样的还是不一样?它们具有不同的 Unicode 编码,重音字符也是如此,但与重音字符不同的是,它们看起来也不同。
æ
ae
这给我们带来了...
阿拉伯语表示形式等效性
阿拉伯文字有一种美丽的书法文化,其中相邻字母的特定序列具有特定的表现形式。其中许多已采用Unicode标准进行编码。我不完全理解这些规则,但在我看来,它们类似于连字。
其他脚本和系统:我完全不懂卡纳达语、马拉雅拉姆语、僧伽罗语、泰语、古吉拉特语、藏语,或者几乎所有没有提到的几十或几百种文字。我认为它们对程序员也有类似的问题,并且考虑到到目前为止提到的问题数量和如此少的脚本,它们可能还有程序员应该考虑的其他问题。
这让我们摆脱了“编码”杂草。
现在我们必须输入“意义”杂草。
等于 ?如果不是,则等于 ?如果不是,为什么不呢?这是拼音罗马化。
Beijing
北京
Bĕijīng
北京
等于 ?如果不是,为什么不呢?这是Wade-Giles的罗马化。
Peking
北京
等于 ?如果不是,为什么不呢?
Beijing
Peking
你为什么要这样做?
例如,如果您想知道两个字符串(A 和 B)是否可能指代同一地理位置或同一个人,您可能需要询问:
这些字符串可能是一组汉字序列的 Wade-Giles 或拼音表示吗?如果是这样,相应的集合之间是否有任何重叠?
这些字符串之一可能是汉字的西里尔文转录吗?
这些字符串之一可能是拼音罗马化的西里尔音译吗?
这些字符串之一可能是拼音罗马化、英文名称汉化的西里尔音译吗?
显然,这些都是困难的问题,没有确切的答案,无论如何,答案可能会根据问题的目的而有所不同。
最后举一个具体的例子。
- 如果您要递送信件或包裹,请明确 、 和 都是平等的。为此,它们都同样出色。毫无疑问,中国邮局认可许多其他选择,例如法语、葡萄牙语、越南语和蒙古语。
Beijing
Peking
Bĕijīng
北京
Pékin
Pequim
Bắc Kinh
Бээжин
单词没有固定的含义。
文字是我们用来驾驭世界、完成任务以及与他人交流的工具。
虽然看起来如果像 、 或 这样的词有固定的含义会有所帮助,但可悲的事实是它们没有。equality
Beijing
meaning
然而,我们似乎以某种方式混淆了。
TL;DR:如果你正在处理与现实有关的问题,在现实的所有模糊性(浑浊、不确定性、缺乏明确的界限)中,每个问题基本上都有三种可能的答案:
- 可能
- 可能不是
- 或
好吧,我遇到了这篇文章,所以我决定对一些流行的答案进行基准测试,简而言之,JaredPar 的答案是最快的,内存分配为 0,而 Colonel Panic 的答案是最慢的
基准信息
- 日期: 2023/05
- .NET SDK:7.0.103.NET SDK:7.0.103.NET SDK:7.0.103.NET SDK.NET
- 基准点网:0.13.5
- 处理器: i3-8100
- 操作系统: Arch Linux
使用的代码
[MemoryDiagnoser]
public class StringContains
{
[Params("How to install Arch Linux?")]
public string Phrase { get; set; }
[Params("How to", "arch", "blazor", "random long string to see if it effects the time needed")]
public string search { get; set; }
[Benchmark(Baseline = true)]
public bool Contains() =>
Phrase.Contains(search, System.StringComparison.CurrentCultureIgnoreCase);
[Benchmark]
public bool toUpper() =>
Phrase.ToUpper().Contains(search.ToUpper());
[Benchmark]
public bool toLower() =>
Phrase.ToLower().Contains(search.ToLower());
[Benchmark]
public bool IndexeOf() =>
Phrase.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0;
[Benchmark]
public bool CultureCompareInfo()
{
var culture = new CultureInfo("en-US");
return culture.CompareInfo.IndexOf(Phrase, search, CompareOptions.IgnoreCase) >= 0;
}
}
结果
我删除了一些列,因为它们并不重要
方法 | 短语 | 搜索 | 意味 着 | 率 | 第 0 代 | 分配 |
---|---|---|---|---|---|---|
包含 | 如何t(...)伊克斯?[26] | 如何 | 46.887纳秒 | 1.00 | - | - |
到上部 | 如何t(...)伊克斯?[26] | 如何 | 88.386纳秒 | 1.89 | 0.0381 | 120 字节 |
到下 | 如何t(...)伊克斯?[26] | 如何 | 87.196纳秒 | 1.86 | 0.0381 | 120 字节 |
索引 | 如何t(...)伊克斯?[26] | 如何 | 19.730纳秒 | 0.42 | - | - |
文化比较信息 | 如何t(...)伊克斯?[26] | 如何 | 166.691纳秒 | 3.56 | 0.0560 | 176 字节 |
包含 | 如何t(...)伊克斯?[26] | 拱 | 98.794纳秒 | 1.00 | - | - |
到上部 | 如何t(...)伊克斯?[26] | 拱 | 86.692纳秒 | 0.88 | 0.0356 | 112 字节 |
到下 | 如何t(...)伊克斯?[26] | 拱 | 70.534纳秒 | 0.71 | 0.0254 | 80 字节 |
索引 | 如何t(...)伊克斯?[26] | 拱 | 26.405纳秒 | 0.27 | - | - |
文化比较信息 | 如何t(...)伊克斯?[26] | 拱 | 219.527纳秒 | 2.22 | 0.0560 | 176 字节 |
包含 | 如何t(...)伊克斯?[26] | Blazor | 118.889纳秒 | 1.00 | - | - |
到上部 | 如何t(...)伊克斯?[26] | Blazor | 83.605纳秒 | 0.70 | 0.0381 | 120 字节 |
到下 | 如何t(...)伊克斯?[26] | Blazor | 67.559纳秒 | 0.57 | 0.0254 | 80 字节 |
索引 | 如何t(...)伊克斯?[26] | Blazor | 13.209纳秒 | 0.11 | - | - |
文化比较信息 | 如何t(...)伊克斯?[26] | Blazor | 229.810纳秒 | 1.93 | 0.0560 | 176 字节 |
包含 | 如何t(...)伊克斯?[26] | 兰多(...)伊迪德 [55] | 95.442纳秒 | 1.00 | - | - |
到上部 | 如何t(...)伊克斯?[26] | 兰多(...)伊迪德 [55] | 113.243纳秒 | 1.19 | 0.0688 | 216 字节 |
到下 | 如何t(...)伊克斯?[26] | 兰多(...)伊迪德 [55] | 86.116纳秒 | 0.90 | 0.0254 | 80 字节 |
索引 | 如何t(...)伊克斯?[26] | 兰多(...)伊迪德 [55] | 7.380纳秒 | 0.08 | - | - |
文化比较信息 | 如何t(...)伊克斯?[26] | 兰多(...)伊迪德 [55] | 217.331纳秒 | 2.28 | 0.0560 | 176 字节 |
传说
Phrase :'Phrase' 参数的值
search :'search' 参数的值
Mean :所有测量值的算术平均值
比率:比率分布的平均值([当前]/[基线])
Gen0:GC 第 0 代每 1000 次操作收集
已分配 :每个操作分配的内存(仅托管,含,1KB = 1024B)
1 ns : 1 纳秒(0.000000001 秒)
.NET 的新版本 具有忽略大小写的功能
examplestring.Contains("exampleSTRING", StringComparison.OrdinalIgnoreCase)
下一个:如何遍历字典?
评论