[C#] 大文字と小文字を区別しない 'Contains(string)'



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");

大文字と小文字は区別されません。現在はどちらも大文字ですが、それはちょっとばかりです。

更新
私が参照する愚かさは、アップケーシングとダウンケーシングに伴う問題です。

更新
この質問は古くからあり、それ以来私は本当に広大で難しい話題について簡単に答えを求めました。
ほとんどの場合、単一言語の英語のコードベースでは、 this回答で十分です。 私はここに来るほとんどの人々がこのカテゴリに入るのでこれが最も一般的な答えだと疑っています。
しかし、 This答えは、両方のテキストが同じ文化であり、その文化が何であるかを知るまで、大文字と小文字を区別しないという固有の問題を引き起こします。 これは多分あまり一般的ではない答えですが、私はそれがより正確であると思うので、私はそのようにマークしました。




これはきれいでシンプルです。

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



これは他の例と非常によく似ていますが、他の選択肢は通常は必要ないので、ブール値に簡単に列挙することにしました。 ここに私の例があります:

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) )
....



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

これは、文字列を含むシーケンスの順序を比較するために機能しstringIEnumerable<char>実装しているため、

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

しかし、わかっているように、文字列は一般的ではなく、特殊化されています。 プレイには2つの重要な要素があります。

  1. それ自体がさまざまな言語に依存するエッジケースを持つ「ケーシング」問題です。
  2. 「テキスト要素」のセット(文字/数字/記号など)がどのようにUnicodeコードポイントによって表現されるか、与えられた文字列を表すことができる有効な文字列はどのように関係するのか?

正味の効果は同じです。 あなたが主張するかもしれない文字列は、言語的に等しいものは、さまざまな文字の組み合わせで有効に表現できます。 さらに、文化間の妥当性のための規則は変わる。

これにより、このような特殊な文字列ベースの "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;
}

この関数は、文字列の正規化が何であれ、大文字小文字を区別せず、カルチャ固有の "contains"を実行するのに使用できます。 例えば

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



string.indexof ()関数を使用することができます。 これは大文字と小文字を区別しません




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



答えの1つの問題は、文字列が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;
} 



ちょうどこのような:

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



初心者のための簡単な方法:

title.ToLower().Contains("string");//of course "string" is lowercase.



Regexを使用した代替ソリューション:

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

通知

@cHaoが彼のコメントで指摘したように、この解決策が間違った結果を返すシナリオがあります。 このソリューションを不本意に実装する前に、あなたが何をしているのかを確認してください。




Links