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

これは常に正しい回数に一致し、無限再帰の問題が発生する可能性はありません。適切な正規表現を変更し、置換データを変更する必要があります。

ただし、Chrisのコメントによると次の点に注意してください。

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 に答える