String.IndexOf() возвращает неожиданный индекс строки

Метод String.IndexOf() работает не так, как я ожидал.

Я ожидал, что он не найдет совпадения, так как точного слова ты нет в str.

string str = "I am your Friend";
int index = str.IndexOf("you",0,StringComparison.OrdinalIgnoreCase);
Console.WriteLine(index);

Выход: 5

Мой ожидаемый результат равен -1, потому что строка не содержит ты.

Вы запрашиваете позицию последовательность символов «вы» в строке, а не позицию слово «вы» в строке. Так как «ваш» начинается с «вы», мы можем сделать вывод, что в строке есть последовательность символов «вы». документация указывает «Сообщает отсчитываемый от нуля индекс первого вхождения указанного символа Unicode или нить в этом экземпляре. Метод возвращает -1, если символ или строка не найдены в этом экземпляре».

DiplomacyNotWar 31.05.2019 06:59

@bolkay Хотя Contains() также сделает вывод, что «ты» находится в строке «Я твой друг».

DiplomacyNotWar 31.05.2019 07:02

Я тыr Друг... похоже, что это там для меня.. если вам нужны границы слов, используйте регулярное выражение или взломайте пробелы слева и справа от вашей строки поиска (однако, вероятно, вызовет больше проблем)

TheGeneral 31.05.2019 07:04

Я подозреваю, что вы хотите string.Split разбить строку на слова. Тогда string.Compare, а не string.IndexOf.

mjwills 31.05.2019 07:10

если вы хотите сохранить большую часть своего кода, вы можете искать «вы» вместо «вы» (просто добавьте пробелы до и после строки «вы»)

D Ie 31.05.2019 07:29

@Dle Будет ли это работать для поиска начального I?

mjwills 31.05.2019 07:32

хорошо, что @mjwills не подумал об этом, это не нашло бы «закрытия» ни у вас, ни у

D Ie 31.05.2019 07:33

А, я перепутал твой смысл. Я получаю 5, а ожидал 5. Строка определенно содержит «вы». Однако он не содержит «вы», но это другая строка.

Davesoft 31.05.2019 09:52

да, Davesoft, вы поняли, поиск функции indexof содержит слово, я имею в виду, что слово «вы» не существует в строке, но все равно он вернет индекс 5, результаты должны быть -1

Nilesh Agotariya 31.05.2019 14:56

Я хочу найти позицию конкретного слова, поэтому из функции indexof я могу получить начальный индекс, но индекс дает неправильный индекс

Nilesh Agotariya 31.05.2019 14:59
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
10
491
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

you является допустимой подстрокой I am your Friend. Если вы хотите узнать, находится ли слово в строке, вы можете разобрать строку методом Split.

char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
string[] words = text.Split(delimiterChars);

А затем загляните внутрь массива. Или превратите его в более удобную для поиска структуру данных.

Если вы хотите выполнять поиск без учета регистра, вы можете использовать следующий код:

char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
string text = "I am your Friend";
// HasSet allows faster lookups in case of big strings
var words = text.Split(delimiterChars).ToHashSet(StringComparer.OrdinalIgnoreCase);
Console.WriteLine(words.Contains("you"));
Console.WriteLine(words.Contains("friend"));

False
True


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

char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
string text = "i am your friend. I Am Your Friend.";
var words = text.Split(delimiterChars);
var dict = new Dictionary<string, List<int>>(StringComparer.InvariantCultureIgnoreCase);
for (int i = 0; i < words.Length; ++i)
{
    if (dict.ContainsKey(words[i])) dict[words[i]].Add(i);
    else dict[words[i]] = new List<int>() { i };
}

Console.WriteLine("youR: ");
dict["youR"].ForEach(i => Console.WriteLine("\t{0}", i));
Console.WriteLine("friend");
dict["friend"].ForEach(i => Console.WriteLine("\t{0}", i));
youR:   
        2   
        7   
friend   
        3   
        8
Ответ принят как подходящий

Проблема, с которой вы столкнулись, заключается в том, что IndexOf соответствует одному символу или последовательности символов (строке поиска) в большей строке. Поэтому «Я твой друг» содержит последовательность «ты». Чтобы сопоставлять только слова, вы должны рассматривать вещи на уровне слов.

Например, вы можете использовать регулярные выражения для сопоставления границ слов:

private static int IndexOfWord(string val, int startAt, string search)
{
    // escape the match expression in case it contains any characters meaningful
    // to regular expressions, and then create an expression with the \b boundary
    // characters
    var escapedMatch = string.Format(@"\b{0}\b", Regex.Escape(search));

    // create a case-sensitive regular expression object using the pattern
    var exp = new Regex(escapedMatch, RegexOptions.IgnoreCase);

    // perform the match from the start position
    var match = exp.Match(val, startAt);

    // if it's successful, return the match index
    if (match.Success)
    {
        return match.Index;
    }

    // if it's unsuccessful, return -1
    return -1;
}

// overload without startAt, for when you just want to start from the beginning
private static int IndexOfWord(string val, string search)
{
    return IndexOfWord(val, 0, search);
}

В вашем примере вы попытаетесь сопоставить \byou\b, что из-за граничных требований не будет соответствовать your.

Попробуйте онлайн

Подробнее о границах слов см. в разделе Регулярные выражения здесь.

Другие вопросы по теме