[c#] غير حساس لحالة الأحرف "يحتوي على (سلسلة)"


10 Answers

يمكنك استخدام الأسلوب StringComparison.OrdinalIgnoreCase وتمرير 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");

لا يبدو أن هناك زيادة في الحجم تسمح لي بوضع حساسية للقضية .. أنا حاليا أحرضهم على حد سواء ، ولكن هذا سخيف فقط.

تحديث
السذاجة التي أشير إليها هي القضايا i18n التي تأتي مع صعودا وهبوطا الغلاف.

تحديث
هذا السؤال قديم ومنذ ذلك الحين أدركت أنني طلبت إجابة بسيطة لموضوع شاسع وصعب حقا إذا كنت تهتم بالتحقيق فيه بشكل كامل.
بالنسبة لمعظم الحالات ، في قواعد اللغة الإنجليزية ، أحادي اللغة ، سوف تكفي this الإجابة. إنني أشك في أن معظم الناس القادمين إلى هنا يندرجون في هذه الفئة وهذا هو الجواب الأكثر شعبية.
ومع ذلك ، فإن This الإجابة تجلب المشكلة المتأصلة التي لا يمكننا مقارنتها بحالة النص إلى أن نعرف أن النصين هما نفس الثقافة ونعرف ما هي تلك الثقافة. ربما تكون هذه إجابة أقل شيوعًا ، لكني أعتقد أنها أكثر صحة وهذا هو السبب الذي جعلني أميزها على هذا النحو.




هذا مشابه تمامًا للمثال الآخر هنا ، لكنني قررت تبسيط التعداد لبولي ، لأن البدائل الأخرى ليست ضرورية عادة. هنا هو مثالى:

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
}



مشكلة واحدة مع الإجابة هي أنه سيتم طرح استثناء إذا كانت سلسلة خالية. يمكنك إضافة ذلك كتحقق بحيث لا:

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



هذا نظيف وبسيط.

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



في النهاية ، تنطلق عملية "تحتوي على" عامة إلى وظيفة كهذه ،

/// <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 s="AbcdEf";
if(s.ToLower().Contains("def"))
{
    Console.WriteLine("yes");
}



طريقة بسيطة لمبتدئ:

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



يكون الأسلوب InStr من تجميع VisualBasic هو الأفضل إذا كان لديك قلق حول internationalization (أو يمكنك إعادة عليه). وبالنظر إلى ذلك ، يُظهِر dotNeetPeek أنه لا يقتصر على الأحرف الكبيرة والصغيرة فقط ، بل ينطبق أيضًا على حروف kana ونوع النص الكامل العرض (ذات الصلة في الغالب باللغات الآسيوية ، على الرغم من وجود إصدارات كاملة الأبجدية الرومانية أيضًا ). أنا أتخطى بعض التفاصيل ، ولكن تحقق من الطريقة الخاصة 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);
}



يمكنك استخدام string.indexof () . سيكون هذا غير حساس لحالة الأحرف




حل بديل باستخدام Regex:

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

تنويه

كما أشارcHao في تعليقه ، هناك سيناريو من شأنه أن يجعل هذا الحل يعود بنتائج غير صحيحة. تأكد من أنك تعرف ما تفعله قبل تنفيذ هذا الحل بشكل عشوائي.




Related