7

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

int index = text.IndexOf("  ");
while (index > 0)
{
    text = text.Replace("  ", " ");
    index = text.IndexOf("  ");
}

一般来说,这工作得很好,尽管相当原始并且可能效率低下。

问题

当文本包含“ - ”出于某种奇怪的原因时 indexOf 返回匹配!Replace 函数不会删除任何内容,然后陷入无限循环。

任何想法 string.IndexOf 发生了什么?

4

1 回答 1

22

啊,文字的乐趣。

你最有可能在那里,但在 SO 上发帖时迷失了,是一个“软连字符”。

为了重现该问题,我在LINQPad中尝试了此代码:

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

果然,上面的代码只是陷入了一个循环。

请注意\u00ad,根据 CharMap,这是软连字符的 Unicode 符号。您也可以随时复制和粘贴 CharMap 中的字符,但将其发布在 SO 上将用其更常见的表亲,连字符减号,Unicode 符号u002d(键盘上的那个)替换它。

您可以阅读String Class文档中的一小部分,其中有关于该主题的内容:

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

我已经强调了相关部分,但我还记得不久前有一篇关于这个确切问题的博客文章,但我的 Google-Fu 今晚让我失望了。

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

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

至少有两种处理方法:

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

    text = Regex.Replace(text, "  +", " ");
    

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

  2. 您可以明确要求 IndexOf 使用序数比较,它不会被表现得像......好吧......文本的文本绊倒:

    index = text.IndexOf("  ", StringComparison.Ordinal);
    
于 2011-02-04T00:11:12.090 回答