奇怪的string.IndexOf行为

And*_*rry 5 c# indexof infinite-loop

我编写了以下代码片段来消除文本块中的过多空格

int index = text.IndexOf("  ");
while (index > 0)
{
    text = text.Replace("  ", " ");
    index = text.IndexOf("  ");
}
Run Code Online (Sandbox Code Playgroud)

一般来说,这种方法很好,虽然相当原始,可能效率低下.

问题

当文本包含" - "的某些bizzare原因时indexOf返回一个匹配!替换功能不会删除任何东西,然后它会卡在无限循环中.

有关string.IndexOf的任何想法吗?

ang*_*son 20

啊,文字的乐趣.

你最有可能在那里,但在SO上发帖时迷路,是一个"软连字符".

为了重现这个问题,我在LINQPad中尝试了这段代码:

void Main()
{
    var text = "Test1 \u00ad Test2";
    int index = text.IndexOf("  ");
    while (index > 0)
    {
        text = text.Replace("  ", " ");
        index = text.IndexOf("  ");
    }
}
Run Code Online (Sandbox Code Playgroud)

果然,上面的代码只是陷入循环中.

请注意\u00ad,根据CharMap,它是Soft Hyphen的Unicode符号.您也可以随时复制并粘贴CharMap中的字符,但是将其发布在SO上会将其替换为更常见的堂兄,连字符号,Unicode符号u002d(键盘上的符号).

您可以阅读String Class的文档中的一小部分,其中有关于此主题的说明:

字符串搜索方法(如String.StartsWith和String.IndexOf)也可以执行区分文化或序数字符串比较.以下示例说明了使用IndexOf方法进行序数比较和文化敏感比较之间的差异.文化敏感搜索,其中当前文化是英语(美国)认为子字符串"oe"匹配连字"œ".因为软连字符(U + 00AD)是零宽度字符,所以搜索将软连字符视为等效于空,并在字符串的开头找到匹配项.另一方面,序数搜索在任何一种情况下都找不到匹配.

我已经突出了相关部分,但我还记得一篇关于这个确切问题的博客文章,但我的Google-Fu今晚失败了.

这里的问题是IndexOf和Replace使用不同的方法来定位文本.

而IndexOf会将软连字符视为"不存在",从而将其两侧的两个空格发现为"两个连接的空格",而Replace方法则不会,因此不会删除它们中的任何一个.因此,循环存在标准以继续迭代,但由于Replace不会删除符合条件的空格,因此它将永远不会结束.毫无疑问,Unicode符号空间中还有其他类似的字符表现出类似的问题,但这是我见过的最典型的情况.

至少有两种处理方式:

  1. 你可以使用Regex.Replace,它似乎没有这个问题:

    text = Regex.Replace(text, "  +", " ");
    
    Run Code Online (Sandbox Code Playgroud)

    就个人而言,我可能会使用正则表达式中的空白特殊字符\s,但是如果你只想要空格,那么上面应该可以解决问题.

  2. 您可以明确要求IndexOf使用序数比较,这不会被文本表现得像......井......文本:

    index = text.IndexOf("  ", StringComparison.Ordinal);
    
    Run Code Online (Sandbox Code Playgroud)