String.Replace does not replace all matches

Why line2does it replace only the alternating half of the entries?

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

Result:

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

I tried using RegEx, but getting similar results.

Is there a better way than this below?

Do While line1.Contains("|CCC|")
    line1 = line1.Replace("|CCC|", "||")
Loop
+5
source share
4 answers

As soon as he finds the first token, he starts looking for the next token after this. Thus, he finds |CCC|, replaces him, then continues, and the first thing he sees is CCC|that which does not match. It does not pre-scan a string that requires token replacement.

Consider this as follows:

Considering AAA|BBB|CCC|CCC|CCC|CCC|EEE|FFF

Run before AAA|BBB|CCC| HOLD IT |CCC| to start building our line:

AAA|BBB+ ||(our replacement)

, CCC|CCC|CCC|EEE|FFF.

CCC|CCC| HOLD IT |CCC|, :

AAA|BBB||CCC + || ( )

, CCC|CCC|EEE|FFF .. ..

EDIT: MSDN, :

, , , oldValue newValue.

, , . MSDN, . , , MSDN.

+8

string.Replace , , , .

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

, VB.

+3

For everyone in the future, I have added an extension method to overcome this limitation within:

<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
+1
source

I could use regex to replace look-around for this case.

Consider the following example:

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

This will always correspond to the correct number of times and is not subject to any endless recursion problems. It requires changing the appropriate regular expression and changing the replacement data.

However, a note on Chris's comment:

Regex.Replace("FCCCF|CCC|CCC||CCC|", "((?<=[|])CCC(?=[|]))", "")
// -> only 5 pipes: verify this is correct per the intended semantics
"FCCCF|||||"
0
source

All Articles