[c#] 不区分大小写'包含(字符串)'



Answers

您可以使用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)开始提供,适用于旧版本

   if(source==null) return false;
   return source.IndexOf(toCheck, comp) >= 0;

用法:

string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
Question

有没有办法让以下回报成真?

string title = "ASTRINGTOTEST";
title.Contains("string");

似乎没有超负荷允许我设置区分大小写。目前,我大写他们两个,但这只是愚蠢的。

UPDATE
我提到的愚蠢是上下套管带来的i18n问题。

UPDATE
这个问题是古老的,从那以后,我意识到我要求一个简单的答案,如果你关心的是一个非常广泛和困难的话题,那么这个问题应该是完全的。
对于大多数情况下,在单语言,英语代码基础上, this答案就足够了。 我怀疑是因为大多数来这里的人都属于这个类别,这是最受欢迎的答案。
然而, This答案带来了固有的问题,即我们无法比较文本不区分大小写,直到我们知道两个文本是相同的文化,并且我们知道这个文化是什么。 这可能是一个不太流行的答案,但我认为它更正确,这就是为什么我这样标记它。




使用Regex的替代解决方案:

bool contains = Regex.IsMatch("StRiNG to search", "string", RegexOptions.IgnoreCase);

注意

正如@cHao在他的评论中指出的那样,有一些情况会导致此解决方案返回不正确的结果。 在你实施这个解决方案之前,确保你知道你在做什么。




VisualBasic程序集的InStr方法是最好的,如果你有关于国际化的问题(或者你可以重新实现它)。 在它看来,dotNeetPeek表明,它不仅涵盖大小写,还包括假名类型和全角与半角字符(主要与亚洲语言相关,尽管也有全角版本的罗马字母)。 我正在跳过一些细节,但请查看私有方法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);
}



这很干净简单。

Regex.IsMatch(file,fileNamestr,RegexOptions.IgnoreCase)



这与其他示例非常相似,但我决定将enum简化为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) )
....



像这样:

string s="AbcdEf";
if(s.ToLower().Contains("def"))
{
    Console.WriteLine("yes");
}



简单的方法为新手:

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
}



最终,通用的“包含”操作归结为这样的功能,

/// <summary>
/// Determines whether the source contains the sequence.
/// </summary>
/// <typeparam name="T">The type of the items in the sequences.</typeparam>
/// <param name="sourceEnumerator">The source enumerator.</param>
/// <param name="sequenceEnumerator">The sequence enumerator.</param>
/// <param name="equalityComparer">An equality comparer.</param>
/// <remarks>
/// An empty sequence will return <c>true</c>.
/// The sequence must support <see cref="IEnumerator.Reset"/>
/// if it does not begin the source.
/// </remarks>
/// <returns>
/// <c>true</c> if the source contains the sequence;
/// otherwise <c>false</c>.
/// </returns>
public static bool Contains<T>(
    IEnumerator<T> sourceEnumerator,
    IEnumerator<T> sequenceEnumerator,
    IEqualityComparer<T> equalityComparer)
{
    if (equalityComparer == null)
    {
        equalityComparer = EqualityComparer<T>.Default;
    }

    while (sequenceEnumerator.MoveNext())
    {
        if (sourceEnumerator.MoveNext())
        {
            if (!equalityComparer.Equals(
                sourceEnumerator.Current,
                sequenceEnumerator.Current))
            {
                sequenceEnumerator.Reset();
            }
        }
        else
        {
            return false;
        }
    }

    return true;
}

这可以简单地包装在接受IEnumerable的扩展版本中,像这样,

public static bool Contains<T>(
        this IEnumerable<T> source,
        IEnumerable<T> sequence,
        IEqualityComparer<T> equalityComparer = null)
{
    if (sequence == null)
    {
        throw new ArgumentNullException("sequence");
    }

    using(var sequenceEnumerator = sequence.GetEnumerator())
    using(var sourceEnumerator = source.GetEnumerator())
    {
        return Contains(
            sourceEnumerator,
            sequenceEnumerator,
            equalityComparer);
    }
}

现在,这将适用于任何序列(包括字符串)的序数比较,因为string实现了IEnumerable<char>

// The optional parameter ensures the generic overload is invoked
// not the string.Contains() implementation.
"testable".Contains("est", EqualityComparer<char>.Default)

但是,正如我们所知,字符串不是通用的,它们是专用的。 有两个关键因素在起作用。

  1. “套管”问题本身具有各种语言相关的边界情况。
  2. 关于一组“文本元素”(字母/数字/符号等)如何由Unicode代码点表示以及什么有效的字符序列可以表示给定字符串的相关问题,在these answers中扩展了详细信息。

净效应是一样的。 您可能声明的字符串在语言上相同,可以通过字符的不同组合来有效表示。 更重要的是,不同文化之间有效性变化的规则。

所有这些都导致了像这样的基于“Contains”实现的专用字符串。

using System.Globalization;

public static bool Contains(
         this string source,
         string value,
         CultureInfo culture = null,
         CompareOptions options = CompareOptions.None)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }

    var compareInfo = culture == null ? 
            CultureInfo.CurrentCulture.CompareInfo :
            culture.CompareInfo;

    var sourceEnumerator = StringInfo.GetTextElementEnumerator(source);
    var sequenceEnumerator = StringInfo.GetTextElementEnumerator(value);

    while (sequenceEnumerator.MoveNext())
    {
        if (sourceEnumerator.MoveNext())
        {
            if (!(compareInfo.Compare(
                    sourceEnumerator.Current,
                    sequenceEnumerator.Current,
                    options) == 0))
            {
                sequenceEnumerator.Reset();
            }
        }
        else
        {
            return false;
        }
    }

    return true;
}

这个函数可以用来执行不区分大小写的文化特定的“包含”,无论标准化字符串如何,它都可以工作。 例如

"testable".Contains("EST", StringComparer.CurrentCultureIgnoreCase)



你可以使用string.indexof ()函数。 这将不区分大小写




答案的一个问题是,如果字符串为空,它将引发异常。 您可以添加,作为一个支票,所以它不会:

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;
} 



Related