Insensibile alle maiuscole 'Contiene (stringa)'


2909

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

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

Sembra che non ci sia un sovraccarico che mi permetta di impostare la distinzione tra maiuscole e minuscole. Attualmente li AGGIORNO entrambi, ma è solo sciocco (con il quale mi riferisco ai problemi di i18n che derivano dal case su e giù).

AGGIORNAMENTO
Questa domanda è antica e da allora mi sono reso conto di aver chiesto una risposta semplice per un argomento davvero vasto e difficile se ti interessa indagare a fondo.
Nella maggior parte dei casi, nelle basi di codice inglese monolingue questa risposta sarà sufficiente. Sospetto perché la maggior parte delle persone che vengono qui rientrano in questa categoria, questa è la risposta più popolare.
Questa risposta, tuttavia, solleva il problema intrinseco che non possiamo confrontare l'insensibilità alle maiuscole e minuscole fino a quando non sappiamo che entrambi i testi sono la stessa cultura e sappiamo cos'è quella cultura. Questa è forse una risposta meno popolare, ma penso che sia più corretta ed è per questo che l'ho contrassegnata come tale.

Risposte:


1398

Per verificare se la stringa paragraphcontiene la stringa word(grazie @QuarterMeister)

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

Dov'è culturel'istanza di CultureInfodescrivere la lingua in cui è scritto il testo.

Questa soluzione è trasparente sulla definizione di insensibilità al maiuscolo / minuscolo, che dipende dalla lingua . Ad esempio, la lingua inglese utilizza i caratteri Ie iper le versioni maiuscole e minuscole della nona lettera, mentre la lingua turca utilizza questi caratteri per l' undicesima e la dodicesima lettera del suo alfabeto di 29 lettere. La versione turca di "i" è il personaggio sconosciuto "İ".

Quindi le stringhe tine TINsono la stessa parola in inglese , ma parole diverse in turco . A quanto ho capito, uno significa "spirito" e l'altro è una parola di onomatopea. (Turchi, per favore correggetemi se sbaglio, o suggerite un esempio migliore)

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


67
Perché no culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0? Utilizza la cultura corretta e non fa distinzione tra maiuscole e minuscole, non alloca stringhe minuscole temporanee ed evita la domanda se la conversione in minuscole e il confronto siano sempre gli stessi di un confronto senza distinzione tra maiuscole e minuscole.
Quartermeister,

9
Questa soluzione inoltre inquina inutilmente l'heap allocando memoria per quella che dovrebbe essere una funzione di ricerca
JaredPar

15
Il confronto con ToLower () darà risultati diversi da un Index insensibile al maiuscolo / minuscolo quando due lettere diverse hanno la stessa lettera minuscola. Ad esempio, chiamando ToLower () su U + 0398 "Lettera maiuscola greca Theta" o U + 03F4 "Simbolo maiuscola greca Theta" si ottiene U + 03B8, "Piccola lettera greca Theta", ma le lettere maiuscole sono considerate diverse. Entrambe le soluzioni considerano le lettere minuscole con la stessa lettera maiuscola diverse, come U + 0073 "Latin Small Letter S" e U + 017F "Latin Small Letter Long S", quindi la soluzione IndexOf sembra più coerente.
Quartermeister,

3
@Quartermeister - e BTW, credo che .NET 2 e .NET4 si comportino diversamente su questo dato che .NET 4 usa sempre NORM_LINGUISTIC_CASING mentre .NET 2 no (questo flag è apparso con Windows Vista).
Simon Mourier,

10
Perché non hai scritto "ddddfg" .IndexOf ("Df", StringComparison.OrdinalIgnoreCase)?
Chen,

2713

È possibile utilizzare il metodo String.IndexOf e passare StringComparison.OrdinalIgnoreCasecome 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 stringa:

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

Si noti che la propagazione nulla ?. è disponibile da C # 6.0 (VS 2015), per l'utilizzo con versioni precedenti

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

USO:

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

3
Ottimo metodo di estensione delle stringhe! Ho modificato il mio per verificare che la stringa di origine non sia nulla per impedire che si verifichino errori di riferimento dell'oggetto durante l'esecuzione di .IndexOf ().
Richard Pursehouse,

8
Questo dà la stessa risposta paragraph.ToLower(culture).Contains(word.ToLower(culture))di CultureInfo.InvariantCulturee non risolve alcun problema di localizzazione. Perché complicare le cose? stackoverflow.com/a/15464440/284795
Colonnello Panic,

60
@ColonelPanic la ToLowerversione include 2 allocazioni che non sono necessarie in un'operazione di confronto / ricerca. Perché allocare inutilmente in uno scenario che non lo richiede?
JaredPar

4
@Seabiscuit che non funzionerà perché non stringè IEnumerable<char>quindi possibile utilizzarlo per trovare sottostringhe
JaredPar

6
Un avvertimento: l'impostazione predefinita per string.IndexOf(string)è l'uso della cultura corrente, mentre l'impostazione predefinita per string.Contains(string)è l'uso del comparatore ordinale. Come sappiamo, il primo può essere modificato selezionando un sovraccarico più lungo, mentre il secondo non può essere modificato. Una conseguenza di questa incoerenza è il seguente esempio di codice:Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string self = "Waldstrasse"; string value = "straße"; Console.WriteLine(self.Contains(value));/* False */ Console.WriteLine(self.IndexOf(value) >= 0);/* True */
Jeppe Stig Nielsen,

231

Puoi usare IndexOf()così:

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 in base zero del valore se viene trovata quella stringa o -1 se non lo è. Se value è String.Empty, il valore restituito è 0.


148

Soluzione alternativa che utilizza Regex:

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

6
Buona idea, abbiamo anche molte combinazioni bit per bit in RegexOptions come RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant;per chiunque se aiuta.
Saravanan,

7
Devo dire che preferisco questo metodo anche se utilizzo IsMatch per pulizia.
vinto il

31
Quel che è peggio, poiché la stringa di ricerca viene interpretata come regex, un certo numero di caratteri di punteggiatura causerà risultati errati (o attiverà un'eccezione a causa di un'espressione non valida). Prova a cercare "."in "This is a sample string that doesn't contain the search string". O prova a cercare "(invalid", per quella materia.
cHao,

17
@cHao: in tal caso, Regex.Escapepotrebbe essere d'aiuto. Regex sembra ancora non necessario quando IndexOf/ extension Containsè semplice (e probabilmente più chiaro).
Dan Mangiarelli,

6
Si noti che non stavo insinuando che questa soluzione Regex fosse il modo migliore di procedere. Stavo semplicemente aggiungendo all'elenco di risposte alla domanda originale pubblicata "Esiste un modo per rendere vero il seguente ritorno?".
Jed,

79

Puoi sempre solo alzare o ridurre le stringhe prima.

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

Oops, ho appena visto l'ultimo pezzo. Un confronto senza distinzione tra maiuscole e minuscole *probabilmente *farebbe comunque lo stesso, e se le prestazioni non sono un problema, non vedo un problema con la creazione di copie maiuscole e il confronto di quelle. Avrei potuto giurare di aver visto una volta un confronto senza distinzione tra maiuscole e minuscole una volta ...


122
Cerca "Test della Turchia" :)
Jon Skeet,

7
In alcune lingue francesi, le lettere maiuscole non hanno i segni diacritici, quindi ToUpper () potrebbe non essere migliore di ToLower (). Direi di usare gli strumenti adeguati, se disponibili - confronto senza distinzione tra maiuscole e minuscole.
Blair Conrad,

5
Non usare ToUpper o ToLower e fai quello che ha detto Jon Skeet
Peter Gfader,

14
L'ho visto di nuovo dopo due anni e un nuovo downvote ... comunque, sono d'accordo che ci sono modi migliori per confrontare le stringhe. Tuttavia, non tutti i programmi saranno localizzati (molti non lo faranno) e molti sono app interne o usa e getta. Dal momento che non posso aspettarmi il credito per i consigli che mi restano meglio per le app usa e getta ... Sto passando: D
Ed S.

8
Cercare "Turchia test" equivale a cercare "TEST TURCHIA"?
JackAce,

55

Solo .NET Core 2.0+ (a partire da ora)

.NET Core ha avuto un paio di metodi per gestirlo dalla versione 2.0:

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

Esempio:

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

Con il passare del tempo, probabilmente entreranno nello standard .NET e, da lì, in tutte le altre implementazioni della libreria di classi base.


1
Ora disponibile anche in .NET Standard 2.1
Paweł Bulwan il

52

Un problema con la risposta è che genererà un'eccezione se una stringa è nulla. Puoi aggiungerlo come segno di spunta in modo che non:

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

8
Se toCheck è la stringa vuota, deve restituire true secondo la documentazione Contiene: "true se il parametro value si trova all'interno di questa stringa o se value è la stringa vuota (" "); in caso contrario, false."
amurra,

3
Sulla base del commento di Amurra sopra, non è necessario correggere il codice suggerito? E questo non dovrebbe essere aggiunto alla risposta accettata, in modo che la risposta migliore sia prima?
David White,

13
Ora questo restituirà vero se source è una stringa vuota o null, indipendentemente da cosa sia CheckCheck. Questo non può essere corretto. Anche IndexOf restituisce già true se toCheck è una stringa vuota e l'origine non è nulla. Ciò che è necessario qui è un controllo per null. Suggerisco se (source == null || value == null) restituisce false;
Colin,

2
La fonte non può essere nulla
Lucas

1
if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck);
Kyle Delaney,

35

La classe StringExtension è la strada da percorrere, ho combinato un paio di post sopra per dare un esempio di codice completo:

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

perché stai permettendo UN ALTRO strato di astrazione StringComparison?
l --''''''--------- '' '' '' '' '' ''

35

Questo è pulito e semplice.

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

31
Questo corrisponderà contro uno schema, però. Nel tuo esempio, se fileNamestrha caratteri speciali regex (ad esempio *, +, ., ecc), allora sarete in per una sorpresa. L'unico modo per far funzionare questa soluzione come una Containsfunzione adeguata è fuggire fileNamestrfacendo Regex.Escape(fileNamestr).
XåpplI'-I0llwlg'I -

inoltre, analizzare e abbinare un regex è molto più dispendioso in termini di risorse rispetto a un semplice confronto senza distinzione tra maiuscole e minuscole
phuclv,

29

OrdinalIgnoreCase, CurrentCultureIgnoreCase o InvariantCultureIgnoreCase?

Dato che manca questo, ecco alcuni consigli su quando usare quale:

dos

  • Uso StringComparison.OrdinalIgnoreCase per i confronti come valore predefinito sicuro per la corrispondenza di stringhe cultura-agnostiche.
  • Usa i StringComparison.OrdinalIgnoreCaseconfronti per aumentare la velocità.
  • Utilizzare le StringComparison.CurrentCulture-basedoperazioni di stringa quando si visualizza l'output per l'utente.
  • Cambia l'uso corrente delle operazioni di stringa in base alla cultura invariante per usare il non linguistico StringComparison.Ordinalo StringComparison.OrdinalIgnoreCasequando il confronto è
    linguisticamente irrilevante (simbolico, ad esempio).
  • Utilizzare ToUpperInvariantpiuttosto che ToLowerInvariantquando si normalizzano le stringhe per il confronto.

cosa non fare

  • Utilizzare gli overload per operazioni su stringhe che non specificano in modo esplicito o implicito il meccanismo di confronto delle stringhe.
  • Utilizzare le operazioni di StringComparison.InvariantCulturestringa basate
    sulla maggior parte dei casi; una delle poche eccezioni sarebbe il
    persistere di 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 della fonte: http://msdn.microsoft.com/en-us/library/ms973919.aspx


cosa succede se sai che otterrai sempre una stringa inglese. quale usare?
BKSpurgeon,

1
@BKSpurgeon Userei OrdinalIgnoreCase, se il caso non ha importanza
Fabian Bigler

20

Queste sono le soluzioni più semplici.

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

11

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

11

Il InStrmetodo dall'assembly VisualBasic è il migliore se si ha una preoccupazione per l'internazionalizzazione (o si potrebbe reimplementarla). Osservandolo, dotNeetPeek mostra che non solo tiene conto di maiuscole e minuscole, ma anche di caratteri kana e caratteri a larghezza intera o a mezza larghezza (principalmente rilevanti per le lingue asiatiche, sebbene esistano 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);
}

11

Proprio come questo:

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

3
Questo non è specifico della cultura e potrebbe non riuscire in alcuni casi. culture.CompareInfo.IndexOf (paragrafo, parola, CompareOptions.IgnoreCase) dovrebbe essere usato.
Hikalkan,


8

Usa questo:

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

26
L'interrogante è alla ricerca di Containsnon Compare.
DuckMaestro l'

@DuckMaestro, la risposta accettata si sta implementando Containscon IndexOf. Quindi questo approccio è ugualmente utile! L'esempio di codice C # in questa pagina sta usando string.Compare (). La scelta del team di SharePoint che è!
corvo vulcanico

6

Questo è abbastanza simile ad altri esempi qui, ma ho deciso di semplificare enum to 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'uso è qualcosa del tipo:

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

6

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

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

4
La tua risposta è esattamente la stessa di guptat59 ma, come è stato sottolineato nella sua risposta, corrisponderà a un'espressione regolare, quindi se la stringa che stai testando contiene speciali caratteri regex non produrrà il risultato desiderato.
Casey,

2
Questa è una copia semplice di questa risposta e soffre degli stessi problemi indicati in quella risposta
Liam,

Concordato. Studia le espressioni regolari
Jared il

5

Solo per basarsi sulla risposta qui, puoi creare un metodo di estensione stringa per renderlo un po 'più user-friendly:

    public static bool ContainsIgnoreCase(this string paragraph, string word)
    {
        return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
    }

1
Supponendo che il tuo paragrafo e la tua parola saranno sempre in USA
Boris Callens,

3
Per evitare problemi con la forzatura della cultura negli Stati Uniti, utilizzare return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;invece.
AndrewWhalan,

3

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

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

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

Questo valore booleano verrà restituito se la stringa è contenuta o meno



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

2

Puoi usare la string.indexof ()funzione. Questo non farà distinzione tra maiuscole e minuscole


2

Il trucco qui è cercare la stringa, ignorando il caso, ma per mantenerlo esattamente lo stesso (con lo stesso caso).

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

L'output è "Ripristina"


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

-4

Modo semplice per i principianti:

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

Downvote per essere semplicemente errato. Cosa succede se title = StRiNg? StRiNg! = String e StRiNg! = STRING
berniefitz

Mi sbagliavo. Modifica la risposta come segue, troppo semplice semplice: <br/> title.ToLower (). Contiene ("stringa") // naturalmente "stringa" è minuscola
O Th Lnh Ldt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.