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




string contains (16)

هل هناك طريقة لجعل العودة التالية صحيحة؟

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

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

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


.NET Core 2.0+ فقط (حتى الآن)

لدى .NET Core زوج من الطرق للتعامل مع هذا منذ الإصدار 2.0:

  • String.Contains (Char، StringComparison )
  • String.Contains (String، StringComparison )

مثال:

"Test".Contains("test", System.StringComparison.CurrentCultureIgnoreCase);

بمرور الوقت ، من المحتمل أن يشقوا طريقهم في .NET Standard ، ومن هناك ، إلى جميع التطبيقات الأخرى لمكتبة Class Class.


إذا كنت تريد التحقق مما إذا كانت السلسلة التي تم تمريرها في السلسلة ، فهناك طريقة بسيطة لذلك.

string yourStringForCheck= "abc";
string stringInWhichWeCheck= "Test abc abc";

bool isContaines = stringInWhichWeCheck.ToLower().IndexOf(yourStringForCheck.ToLower()) > -1;

This boolean value will return if string contains or not

الخدعة هنا هي البحث عن السلسلة ، تجاهل الحالة ، ولكن للحفاظ عليها تمامًا (مع نفس الحالة).

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

الإخراج هو "إعادة تعيين"


تماما مثل هذا:

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

فئة 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;
    }
}

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

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

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

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

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

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

هذه هي أسهل الحلول.

  1. حسب مؤشر

    string title = "STRING";
    
    if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
    {
        // contains 
    }
    
  2. عن طريق تغيير الحالة

    string title = "STRING";
    
    bool contains = title.ToLower().Contains("string")
    
  3. بواسطة Regex

    Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
    

وأنا أعلم أن هذا ليس 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");

يكون الأسلوب 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);
}

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

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


يمكنك دائمًا رفع أو إلغاء السلاسل أولاً.

string title = "string":
title.ToUpper().Contains("STRING")  // returns true

عفوًا ، لقد رأيت ذلك الجزء الأخير. من المحتمل أن تؤدي * المقارنة غير الحساسة لحالة الأحرف * نفس الشيء على أية حال ، وإذا لم يكن الأداء مشكلة ، فأنا لا أرى مشكلة في إنشاء نسخ كبيرة ومقارنة تلك. استطعت أن أقسم بأنني رأيت مرة واحدة غير حساسة لحالة مقارنة مرة واحدة ...


OrdinalIgnoreCase ، CurrentCultureIgnoreCase أو InvariantCultureIgnoreCase؟

نظرًا لأن هذا مفقود ، إليك بعض التوصيات حول وقت استخدام أي منها:

دوس

  • استخدم StringComparison.OrdinalIgnoreCase لإجراء المقارنات كإعداد افتراضي آمن لمطابقة سلسلة StringComparison.OrdinalIgnoreCase بين الثقافات.
  • استخدم مقارنات StringComparison.OrdinalIgnoreCase لزيادة السرعة.
  • استخدم عمليات السلسلة StringComparison.CurrentCulture-based سلسلة 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


if ("strcmpstring1".IndexOf(Convert.ToString("strcmpstring2"), StringComparison.CurrentCultureIgnoreCase) >= 0){return true;}else{return false;}






case-insensitive