c# list - Case insensitive 'Contains(string)'




vb net (21)

OrdinalIgnoreCase, CurrentCultureIgnoreCase o InvariantCultureIgnoreCase?

Poiché questo manca, ecco alcuni consigli su quando utilizzare quale:

dos

  • Usa StringComparison.OrdinalIgnoreCase per i confronti come predefinito sicuro per la corrispondenza stringa indipendente dalla cultura.
  • Usa confronti StringComparison.OrdinalIgnoreCase per aumentare la velocità.
  • Utilizzare le operazioni stringa StringComparison.CurrentCulture-based quando si visualizza l'output per l'utente.
  • Cambiare l'uso corrente delle operazioni stringa sulla base della cultura invariabile per utilizzare StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase non linguistico quando il confronto è
    linguisticamente irrilevante (simbolico, per esempio).
  • Utilizzare ToUpperInvariant anziché ToLowerInvariant durante la normalizzazione delle stringhe per il confronto.

cosa non fare

  • Utilizzare gli overload per le operazioni sulle stringhe che non specificano esplicitamente o implicitamente il meccanismo di comparazione delle stringhe.
  • Usa stringa StringComparison.InvariantCulture
    operazioni nella maggior parte dei casi; una delle poche eccezioni sarebbe
    persistenti dati linguisticamente significativi ma culturalmente-agnostici.

Sulla base di queste regole dovresti usare:

string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.[YourDecision]) != -1)
{
    // The string exists in the original
}

mentre [YourDecision] dipende dalle raccomandazioni di cui sopra.

collegamento di origine: http://msdn.microsoft.com/en-us/library/ms973919.aspx

C'è un modo per rendere il seguente ritorno vero?

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

Non sembra esserci un sovraccarico che mi permetta di impostare la distinzione tra maiuscole e minuscole. Attualmente li UPPERCASE entrambi, ma questo è semplicemente sciocco (con cui mi riferisco ai problemi i18n che hanno un involucro alto e basso).

AGGIORNARE
Questa domanda è antica e da allora mi sono reso conto che ho chiesto una risposta semplice per un argomento davvero vasto e difficile se ti interessa investigarlo completamente.
Per la maggior parte dei casi, in base al codice in lingua inglese, this risposta sarà sufficiente. Sospetto che la maggior parte della gente che viene qui cada in questa categoria è la risposta più popolare.
This risposta, tuttavia, fa emergere il problema intrinseco che non possiamo confrontare il maiuscolo / minuscolo del testo fino a quando non sappiamo che entrambi i testi sono la stessa cultura e sappiamo che cos'è questa cultura. Questa è forse una risposta meno popolare, ma penso che sia più corretta ed è per questo che l'ho contrassegnata come tale.


L'uso di una RegEx è un modo semplice per farlo:

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

Per verificare se il paragraph stringa contiene la word stringa (grazie @QuarterMeister)

culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0

Dove culture è l'istanza di CultureInfo descrive la lingua in cui è scritto il testo.

Questa soluzione è trasparente sulla definizione di insensibilità alle maiuscole e minuscole, che dipende dalla lingua . Ad esempio, la lingua inglese utilizza i caratteri I e i per le versioni maiuscole e minuscole della nona lettera, mentre la lingua turca usa questi caratteri per l' undicesima e la dodicesima lettera dell'alfabeto lungo 29 lettere. La versione turca di "i" è il carattere non familiare "©".

Quindi le stringhe tin e TIN sono la stessa parola in inglese , ma diverse parole in turco . Come ho capito, uno significa "spirito" e l'altro è una parola onomatopeica. (Turchi, per favore correggimi se sbaglio o suggerisci un esempio migliore)

Per riassumere, puoi solo rispondere alla domanda "queste due stringhe sono le stesse ma in diversi casi" se sai in che lingua si trova il testo . Se non lo sai, dovrai prendere un punt. Data l'egemonia inglese nel software, dovresti probabilmente ricorrere a CultureInfo.InvariantCulture , perché sarà sbagliato in modi familiari.


se si desidera verificare se la stringa passata è in stringa, esiste un metodo semplice.

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

In definitiva, un'operazione generica "contiene" si riduce a una funzione come questa,

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

questo può essere banalmente racchiuso in una versione di estensione che accetta IEnumerable come questo,

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

Ora, questo funzionerà per il confronto ordinale di tutte le sequenze, incluse le stringhe, poiché la string implementa IEnumerable<char> ,

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

Tuttavia, come sappiamo, le stringhe non sono generiche, sono specializzate. Ci sono due fattori chiave in gioco.

  1. Il problema del "casing" che a sua volta ha diversi casi limite dipendenti dalla lingua.
  2. La questione piuttosto complessa di come un insieme di "Elementi di testo" (lettere / numeri / simboli ecc.) Sono rappresentati da Unicode Code Points e quali sequenze valide di caratteri possono rappresentare una determinata stringa, i dettagli vengono espansi in these answers .

L'effetto netto è lo stesso. Le stringhe che potresti affermare sono linguisticamente uguali possono essere validamente rappresentate da diverse combinazioni di caratteri. Cosa c'è di più, le regole per la validità cambiano tra culture.

Tutto ciò porta a un'implementazione "Contains" basata su string specializzata come questa.

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

Questa funzione può essere utilizzata per eseguire una distinzione tra maiuscole e minuscole, "contiene" specifici della cultura che funzioneranno, indipendentemente dalla normalizzazione delle stringhe. per esempio

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

Usa questo:

string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);

Proprio come questo:

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

Questo è abbastanza simile ad un altro esempio qui, ma ho deciso di semplificare enum per bool, primario perché normalmente non sono necessarie altre alternative. Ecco il mio esempio:

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

E l'utilizzo è qualcosa come:

if( "main String substring".Contains("SUBSTRING", true) )
....

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

Il metodo InStr dall'assembly VisualBasic è il migliore se si ha una preoccupazione per l'internazionalizzazione (o si potrebbe reimplementarla). Guardando in esso, dotNeetPeek mostra che non solo tiene conto di maiuscole e minuscole, ma anche di caratteri kana e di caratteri pieni e semi-larghi (principalmente rilevanti per le lingue asiatiche, sebbene ci siano anche versioni a larghezza intera dell'alfabeto romano) ). Sto saltando alcuni dettagli, ma controlla il metodo privato 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);
}

Modo semplice per principianti:

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

Queste sono le soluzioni più facili.

  1. Per indice di

    string title = "STRING";
    
    if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
    {
        // contains 
    }
    
  2. Cambiando caso

    string title = "STRING";
    
    bool contains = title.ToLower().Contains("string")
    
  3. Di Regex

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

Soluzione alternativa con Regex:

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

Avviso

Come ha sottolineato @cHao nel suo commento, ci sono degli scenari che causeranno che questa soluzione restituisca risultati errati. Assicurati di sapere cosa stai facendo prima di implementare questa soluzione a caso.


Solo .NET Core 2.0+ (al momento)

.NET Core ha avuto un paio di metodi per risolvere questo problema dalla versione 2.0:

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

Esempio:

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

Col tempo, probabilmente si faranno strada nello standard .NET e, da lì, in tutte le altre implementazioni della Base Class Library.


So che questo non è il C #, ma nel framework (VB.NET) esiste già una tale funzione

Dim str As String = "UPPERlower"
Dim b As Boolean = InStr(str, "UpperLower")

Variante C #:

string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");

Questo è pulito e semplice.

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

Puoi usare IndexOf() questo modo:

string title = "STRING";

if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
{
    // The string exists in the original
}

Poiché 0 (zero) può essere un indice, si controlla contro -1.

MSDN

La posizione dell'indice di valore a base zero se tale stringa viene trovata o -1 se non lo è. Se value è String.Empty, il valore restituito è 0.


È possibile utilizzare il metodo String.IndexOf e passare StringComparison.OrdinalIgnoreCase come tipo di ricerca da utilizzare:

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

Ancora meglio sta definendo un nuovo metodo di estensione per la stringa:

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

Nota, quella propagazione nulla ?. è disponibile da C # 6.0 (VS 2015), per le versioni precedenti

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

USO:

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

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
}

È possibile utilizzare la funzione string.indexof () . Questo sarà case insensitive


Preferisco i tipi .NET maiuscolo (piuttosto che gli alias) per motivi di formattazione. I tipi .NET sono colorati come gli altri tipi di oggetto (i tipi di valore sono oggetti appropriati, dopo tutto).

Le parole chiave condizionali e di controllo (come if , switch e return ) sono in minuscolo e di colore blu scuro (impostazione predefinita). E preferirei non avere il disaccordo in uso e formato.

Tenere conto:

String someString; 
string anotherString; 




c# string contains case-insensitive