String.IndexOf () возвращает неожиданный индекс строки - PullRequest
0 голосов
/ 31 мая 2019

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

Я ожидал, что совпадение не будет найдено, поскольку точное слово you отсутствует в str.

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

Выход: 5

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

Ответы [ 2 ]

7 голосов
/ 31 мая 2019

Проблема, с которой вы сталкиваетесь, заключается в том, что 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.

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

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

2 голосов
/ 31 мая 2019

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

Ложная
Правда


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

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