String.IndexOf() returns 意外的字符串索引

String.IndexOf() returns unexpected index of string

String.IndexOf() 方法未按预期运行。

我预计它找不到匹配项,因为确切的词 you 不在 str.

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

输出:5

我的预期结果是 -1 因为字符串不包含 you.

youI am your Friend 的有效子串。如果您想查找某个单词是否在字符串中,您可以 parse the string with Split method.

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

然后查看数组内部。或者把它变成更多的lookup-friendly数据结构。

如果您想搜索 case-insensitive 可以使用以下代码:

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


创建字典如下code-snippet您可以快速检查所有单词的所有位置。

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 匹配较大字符串中的单个字符或字符序列(搜索字符串)。因此 "I am your friend" 包含序列 "you"。只匹配单词,就得从单词层面考虑。

例如,您可以使用正则表达式匹配单词边界:

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

Try it online

在正则表达式中查看有关单词边界的更多信息 here