5

为什么line2只替换交替出现的一半?

    Dim line1 As String = "AAA|BBB|CCC|CCC|CCC|CCC|EEE|FFF"
    Dim line2 As String = "AAA|BBB|CCC|CCC|CCC|CCC|EEE|FFF"
    Dim line3 As String = "AAA|BBB|CCC|CCC|CCC|CCC|EEE|FFF"

    line1 = line1.Replace("CCC", "")
    line2 = line2.Replace("|CCC|", "||")
    line3 = line3.Replace("CCC|", "|")

结果:

line1 = "AAA|BBB|||||EEE|FFF" -- OK, but fails when element is "..|ZZZCCCZZZ|.."
line2 = "AAA|BBB||CCC||CCC|EEE|FFF" -- Not OK
line3 = "AAA|BBB|||||EEE|FFF" -- OK, but fails similar to Line1 edge-case for "..|ZZZCCC|.."

我曾尝试使用 RegEx,但得到了类似的结果。

下面真的没有比这更好的方法了吗?

Do While line1.Contains("|CCC|")
    line1 = line1.Replace("|CCC|", "||")
Loop
4

4 回答 4

9

一旦找到第一个令牌,它就会开始寻找该令牌之后的一个令牌。所以它找到,替换它,然后继续,它看到的第一件事就是不匹配。它不会预先扫描字符串以查找要替换的标记。|CCC|CCC|

像这样考虑它:

给定AAA|BBB|CCC|CCC|CCC|CCC|EEE|FFF

它运行到AAA|BBB|CCC| HOLD IT |CCC|被发现,让我们开始构建我们的字符串:

AAA|BBB+ ||(我们的替代品)

现在让我们继续前进,我们现在已经CCC|CCC|CCC|EEE|FFF离开了。

它运行到CCC|CCC| HOLD IT |CCC|被发现,让我们继续添加到我们的字符串:

AAA|BBB||CCC+ ||(我们的替代品)

现在让我们继续前进,我们现在有CCC|CCC|EEE|FFF等等等等。

编辑:考虑MSDN上描述返回值的条目:

与当前字符串等效的字符串,除了 oldValue 的所有实例都替换为 newValue。

人们可以将其解读为您期望它预扫描字符串并找到所有匹配项。我在 MSDN 文档中没有看到任何描述这种极端情况的内容。也许这是应该添加到 MSDN 文档中的内容。

于 2013-02-05T17:58:41.587 回答
3

不要使用正则表达式或者string.Replace您可以解析值,而是过滤您不想要的值并将它们重新连接在一起。

line1 = string.Join("|", line1.Split("|").Select(s => s == "CCC" ? "" : s).ToArray());

对不起,我不知道 VB 等价物。

于 2013-02-05T18:24:48.180 回答
1

对于未来的任何人,我添加了一个扩展方法来克服框架中的这个限制:

<System.Runtime.CompilerServices.Extension()>
Public Function ReplaceAll(ByVal original As String, ByVal oldValue As String, ByVal newValue As String) As String

    If newValue.Contains(oldValue) Then
        Throw New ArgumentException("New value can't be a subset of OldValue as infinite replacements can occur.", newValue)
    End If

    Dim maxIterations As Integer = original.Length \ oldValue.Length

    While maxIterations > 0 AndAlso original.Contains(oldValue)
        original = original.Replace(oldValue, newValue)
        maxIterations -= 1
    End While

    Return original

End Function
于 2013-02-05T18:44:05.160 回答
0

对于这种情况,我可能会使用正则表达式替换环视。

考虑这个例子:

Regex.Replace("FCCCF|CCC|CCC|", "((?<=[|])CCC(?=[|]))", "")
// ->
"FCCCF|||"

这将始终匹配正确的次数,并且不容易出现任何无限递归问题。它需要修改适当的正则表达式并更改替换数据。

但是,请注意克里斯的评论:

Regex.Replace("FCCCF|CCC|CCC||CCC|", "((?<=[|])CCC(?=[|]))", "")
// -> only 5 pipes: verify this is correct per the intended semantics
"FCCCF|||||"
于 2013-02-05T20:08:34.117 回答