Без учета регистра 'Содержит (строка)'

2534

Есть ли способ сделать следующее возвращение истинным?

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

Кажется, что нет перегрузки, которая позволяет мне установить чувствительность к регистру. В настоящее время я ВЕРХНИЙ их обоих, но это просто глупо (к чему я имею в виду проблемы i18n, которые поставляются с up- и нижним корпусом).

ОБНОВИТЬ
Этот вопрос древний, и с тех пор я понял, что попросил простой ответ на очень обширную и трудную тему, если вы хотите изучить ее полностью.
В большинстве случаев в моноязычных, английских кодовых базах этот ответ будет достаточным. Я подозреваю, что большинство людей, приезжающих сюда, попадают в эту категорию, это самый популярный ответ.
Однако этот ответ порождает неотъемлемую проблему, по которой мы не можем сравнивать текстовый регистр без учета, пока мы не узнаем, что оба текста являются одной и той же культурой, и мы знаем, что это за культура. Это, возможно, менее популярный ответ, но я думаю, что это более правильно, и поэтому я отметил его как таковой.

Теги:
string
contains
case-insensitive

24 ответа

1108
Лучший ответ

Чтобы проверить, содержит ли строка paragraph строку word (спасибо @QuarterMeister)

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

Где culture - это экземпляр CultureInfo, описывающий язык, на котором написан текст.

Это решение прозрачно относительно определения нечувствительности к регистру, которое зависит от языка. Например, английский язык использует символы I и I для верхних и нижних версий девятой буквы, тогда как турецкий язык использует эти символы для одиннадцатая и двенадцатая буквы его 29-буквенного алфавита. Турецкая версия "i" в верхнем регистре - это незнакомый персонаж "İ".

Таким образом, строки tin и tin являются одним и тем же словом на английском языке, но разные слова на турецком языке. Насколько я понимаю, один означает "дух", а другой - слово звукоподражания. (Турки, пожалуйста, поправьте меня, если я ошибаюсь, или предложите лучший пример)

Подводя итог, вы можете ответить только на вопрос: "Эти две строки одинаковы, но в разных случаях", если вы знаете, на каком языке находится текст. Если вы не знаете, вам придется взять пунт. Учитывая английскую гегемонию в программном обеспечении, вы, вероятно, должны прибегать к CultureInfo.InvariantCulture, потому что это будет неправильно по-дружески.

  • 0
    Я понимаю вашу точку зрения, и вы, вероятно, правы. Этот вопрос древний, и мне нужно перечитать его снова, но я думаю, что я изменю принятый ответ.
  • 58
    Почему не culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0 ? Он использует правильную культуру и нечувствителен к регистру, он не выделяет временные строчные буквы, и он избегает вопроса о том, всегда ли преобразование в строчные буквы и сравнение всегда то же самое, что и сравнение без учета регистра.
Показать ещё 15 комментариев
2439

Вы можете использовать метод String.IndexOf и передать 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;
    }
}

Заметим, что нулевое распространение ?. доступен с С# 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);
  • 1
    Где было бы лучше всего поместить что-то подобное в структуру приложения?
  • 1
    @Анди, у меня обычно есть пара файлов кода с методами расширения общего назначения, куда это пойдет.
Показать ещё 20 комментариев
209

Вы можете использовать IndexOf() следующим образом:

string title = "STRING";

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

Так как 0 (ноль) может быть индексом, вы проверяете -1. ​​

MSDN

Значение индекса, основанного на нулевом значении, если эта строка найдена, или -1 если это не так. Если значением является String.Empty, возвращаемое значение равно 0.

118

Альтернативное решение с использованием Regex:

bool contains = Regex.IsMatch("StRiNG to search", Regex.Escape("string"), RegexOptions.IgnoreCase);
  • 5
    Хорошая идея, также у нас есть много побитовых комбинаций в RegexOptions, таких как RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant; для всех, если поможет.
  • 7
    Должен сказать, что я предпочитаю этот метод, хотя использую IsMatch для аккуратности.
Показать ещё 6 комментариев
64

Вы всегда можете просто перевернуть строки вниз.

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

Ой, просто увидел этот последний бит. Нечувствительность к регистру не могла бы совпадать с t21, вероятно, *, и если производительность не является проблемой, я не вижу проблемы с созданием заглавных копий и их сравнением. Я мог бы поклясться, что однажды увидел случай, когда нечувствительность к регистру...

  • 3
    Интересно, что я видел ToUpper (), рекомендованный для использования ToLower () в такого рода сценариях, потому что, очевидно, ToLower () может «потерять точность» в определенных культурах, то есть два разных символа в верхнем регистре переводятся в один и тот же строчные буквы
  • 105
    Поиск "Турция тест" :)
Показать ещё 7 комментариев
46

Одна из проблем с ответом заключается в том, что он генерирует исключение, если строка равна null. Вы можете добавить это как проверку, чтобы это не было:

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
    Если toCheck - пустая строка, она должна возвращать true в соответствии с документацией Contains: "true, если параметр value встречается в этой строке или значение является пустой строкой (" "); в противном случае - false."
  • 3
    Основываясь на комментарии Амурры выше, нужно ли исправлять предложенный код? И не следует ли добавить это к принятому ответу, чтобы лучший ответ был первым?
Показать ещё 4 комментария
33

Класс 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;
    }
}
32

Это чисто и просто.

Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)
  • 24
    Это будет соответствовать шаблону, хотя. В вашем примере, если fileNamestr имеет какие-либо специальные символы регулярных выражений (например, * , + fileNamestr т . Д.), Вас ждет сюрприз. Единственный способ заставить это решение работать как правильная функция Contains - это экранировать fileNamestr , выполнив Regex.Escape(fileNamestr) .
23

OrdinalIgnoreCase, CurrentCultureIgnoreCase или InvariantCultureIgnoreCase?

Так как этого не хватает, вот некоторые рекомендации о том, когда использовать какой:

Dos

  • Используйте StringComparison.OrdinalIgnoreCase для сравнения как ваш безопасный по умолчанию для сопоставления между культурами и агностиками.
  • Используйте сравнения StringComparison.OrdinalIgnoreCase для увеличения скорости.
  • Используйте операции StringComparison.CurrentCulture-based string при отображении вывода пользователю.
  • Включить текущее использование строковых операций на основе инварианта культуре использовать нелингвистические 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

  • 0
    Что если ты знаешь, что всегда получишь английскую строку. какой использовать?
  • 1
    @BKSpurgeon я бы использовал OrdinalIgnoreCase, если случай не имеет значения
11

Точно так же:

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

Метод InStr из сборки VisualBasic является лучшим, если вы беспокоитесь о интернационализации (или вы можете переопределить его). Глядя на него, 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);
}
10

Я знаю, что это не С#, но в рамках (VB.NET) уже есть такая функция

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

Вариант С#:

string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");
  • 0
    Вы также знаете, как это работает внутри?
9

Используйте это:

string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);
  • 25
    Опрашивающий ищет Contains не Compare .
  • 0
    @ DuckMaestro, принятый ответ реализует Contains с IndexOf . Так что этот подход одинаково полезен! Пример кода C # на этой странице использует string.Compare (). Выбор команды SharePoint это!
8

В конечном итоге общая операция "содержит" сводится к такой функции,

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

Однако, как известно, строки не являются общими, они специализированы. В игре играют два ключевых фактора.

  • Проблема "обсадной колонны", которая сама по себе имеет различные случаи, зависящие от языка.
  • Довольно сложная проблема в том, как набор "текстовых элементов" (буквы/цифры/символы и т.д.) представлены кодовыми точками Юникода и какие действительные последовательности символов могут представлять заданную строку, детали расширяются в эти ответы.

Чистый эффект тот же. Строки, которые вы можете утверждать, являются лингвистически равными, могут быть справедливо представлены различными комбинациями символов. Более того, правила действительности изменяются между культурами.

Все это приводит к реализации специализированной строки на основе "Содержит", как это.

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

Это самые простые решения.

  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);
    
  • 0
    Большое спасибо, благодаря первому примеру !!!
6

Использование RegEx - это прямой способ сделать это:

Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
  • 4
    Ваш ответ точно такой же, как у guptat59, но, как было указано в его ответе, он будет соответствовать регулярному выражению, поэтому, если тестируемая строка содержит какие-либо специальные символы регулярного выражения, она не даст желаемого результата.
  • 2
    Это прямая копия этого ответа и страдает от тех же проблем, которые отмечены в этом ответе
Показать ещё 2 комментария
5

Это очень похоже на другой пример здесь, но я решил упростить enum для bool, потому что другие альтернативы обычно не нужны. Вот мой пример:

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

Только для.NET Core 2. 0+ (на данный момент)

.NET Core имеет пару методов для решения этой проблемы начиная с версии 2.0:

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

Пример:

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

Со временем они, вероятно, перейдут в стандарт.NET, а оттуда во все другие реализации библиотеки базовых классов.

  • 2
    В заключение ! Потребовалось много времени, чтобы быть доступным ...
2

Вы можете использовать функцию string.indexof (). Это будет нечувствительным к регистру

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

Трюк здесь заключается в том, чтобы искать строку, игнорируя регистр, но сохранить его точно таким же (с тем же случаем).

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

Выход "Reset"

0

если вы хотите проверить, находится ли ваша строка в строке, тогда для этого существует простой способ.

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
0
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
}
-3

Простой способ для новичков:

title.ToLower().Contains("string");//of course "string" is lowercase.
  • 1
    Нет, это не полностью решает проблему.
  • 0
    Даунвот за то, что просто неверен. Что если title = StRiNg? StRiNg! = Строка и StRiNg! = STRING
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню