[C#] Groß- / Kleinschreibung beachten "Enthält (Zeichenfolge)"



Answers

Sie könnten die String.IndexOf-Methode verwenden und StringComparison.OrdinalIgnoreCase als den Typ der zu verwendenden Suche übergeben:

string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;

Noch besser ist es, eine neue Erweiterungsmethode für string zu definieren:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source?.IndexOf(toCheck, comp) >= 0;
    }
}

Beachten Sie, dass die Nullfortpflanzung ?. ist seit C # 6.0 (VS 2015) für ältere Versionen verfügbar

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

VERWENDUNG:

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

Gibt es eine Möglichkeit, die folgende Rückkehr wahr zu machen?

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

Es scheint keine Überlastung zu geben, die es mir erlaubt, die Groß- / Kleinschreibung festzulegen. Zurzeit veröffentliche ich sie beide, aber das ist nur albern.

AKTUALISIEREN
Die Dummheit, auf die ich mich beziehe, ist die Probleme, die mit Up-und Down-Gehäuse kommen.

AKTUALISIEREN
Diese Frage ist alt und seitdem habe ich erkannt, dass ich um eine einfache Antwort für ein wirklich großes und schwieriges Thema gebeten habe, wenn Sie es gründlich untersuchen wollen.
In den meisten Fällen reicht this Antwort in einsprachigen englischen Codebasen aus. Ich vermute, weil die meisten Leute, die hierher kommen, in diese Kategorie fallen, ist dies die beliebteste Antwort.
This Antwort wirft jedoch das inhärente Problem auf, dass wir die Groß- / Kleinschreibung nicht vergleichen können, bis wir wissen, dass beide Texte die gleiche Kultur sind und wir wissen, was diese Kultur ist. Dies ist vielleicht eine weniger populäre Antwort, aber ich denke, es ist korrekter und deshalb habe ich es als solches markiert.




Einfacher Weg für Neulinge:

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



Alternative Lösung mit Regex:

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

Beachten

Wie @cHao in seinem Kommentar darauf hingewiesen hat, gibt es Szenarien, die dazu führen, dass diese Lösung falsche Ergebnisse liefert. Stellen Sie sicher, dass Sie wissen, was Sie tun, bevor Sie diese Lösung planlos implementieren.




Ein Problem mit der Antwort ist, dass eine Ausnahme ausgelöst wird, wenn eine Zeichenfolge null ist. Sie können das als Kontrolle hinzufügen, damit es nicht funktioniert:

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



Letztendlich kommt eine generische "contains" Operation auf eine Funktion wie diese,

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

Dies kann trivialerweise in einer Erweiterungsversion verpackt werden, die IEnumerable akzeptiert.

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

Nun wird dies für den ordinalen Vergleich beliebiger Sequenzen, einschließlich Strings, IEnumerable<char> , da string IEnumerable<char> implementiert,

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

Wie wir jedoch wissen, sind Strings nicht generisch, sie sind spezialisiert. Es gibt zwei Schlüsselfaktoren im Spiel.

  1. Das "Casing" -Problem, das selbst verschiedene sprachabhängige Randfälle aufweist.
  2. Die ziemlich komplizierte Frage, wie ein Satz von "Textelementen" (Buchstaben / Zahlen / Symbole usw.) durch Unicode-Codepunkte repräsentiert wird und welche gültigen Folgen von Zeichen eine gegebene Zeichenkette darstellen können, werden in these answers .

Der Nettoeffekt ist der gleiche. Strings, von denen Sie behaupten können, dass sie sprachlich gleich sind, können durch verschiedene Kombinationen von Zeichen gültig dargestellt werden. Darüber hinaus ändern sich die Regeln für die Gültigkeit zwischen den Kulturen.

All dies führt zu einer spezialisierten String-basierten "Contains" -Implementierung.

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

Diese Funktion kann verwendet werden, um ein case-insensitives, kulturspezifisches "contains" auszuführen, das unabhängig von der Normalisierung der Strings funktioniert. z.B

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



Die InStr Methode aus der VisualBasic-Assembly ist am besten, wenn Sie Bedenken hinsichtlich der Internationalisierung haben (oder Sie könnten sie erneut implementieren). Betrachtet man dotNetPeek, so zeigt es, dass es nicht nur Groß- und Kleinbuchstaben berücksichtigt, sondern auch Kana-Typen und Zeichen voller Breite und halber Breite (hauptsächlich relevant für asiatische Sprachen, obwohl es auch Vollbreitenversionen des lateinischen Alphabets gibt ). Ich überspringe einige Details, aber überprüfe die private Methode 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);
}



Sie können die Funktion string.indexof () verwenden. Dies wird nicht zwischen Groß- und Kleinschreibung unterschieden




Genau wie dieser:

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



Das ist sauber und einfach.

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



Dies ist ziemlich ähnlich zu anderen Beispielen hier, aber ich habe beschlossen, enum zu bool, primary zu vereinfachen, weil andere Alternativen normalerweise nicht benötigt werden. Hier ist mein Beispiel:

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

Und die Verwendung ist etwas wie:

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
}



Links