311

%FirstName%文字列を検索し、出現するすべてのand%PolicyAmount%をデータベースから取得した値に置き換える必要があります。問題は、FirstName の大文字と小文字が異なることです。これにより、String.Replace()メソッドを使用できなくなります。このテーマに関するウェブページを見たことがあります。

Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);

しかし、何らかの理由で に置き換えようと%PolicyAmount%すると$0、置き換えが行われません。ドル記号が正規表現の予約文字であることと関係があると思います。

正規表現の特殊文字を処理するために入力をサニタイズする必要のない別の方法はありますか?

4

16 に答える 16

298

引数を取るオーバーロードがstring.Replace 必要なようです。StringComparisonそうではないので、次のようなことを試すことができます:

public static string ReplaceString(string str, string oldValue, string newValue, StringComparison comparison)
{
    StringBuilder sb = new StringBuilder();

    int previousIndex = 0;
    int index = str.IndexOf(oldValue, comparison);
    while (index != -1)
    {
        sb.Append(str.Substring(previousIndex, index - previousIndex));
        sb.Append(newValue);
        index += oldValue.Length;

        previousIndex = index;
        index = str.IndexOf(oldValue, index, comparison);
    }
    sb.Append(str.Substring(previousIndex));

    return sb.ToString();
}
于 2008-10-28T21:27:58.307 に答える
134

MSDN
$0 から - 「グループ番号 number (10 進数) に一致した最後の部分文字列を置換します。」

.NET 正規表現では、グループ 0 は常に一致全体です。リテラル $ の場合は、

string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$$0", RegexOptions.IgnoreCase);
于 2008-10-28T19:47:10.943 に答える
45

一部には、質問のタイトルが実際に尋ねられている特定の質問よりもはるかに大きいため、一種の紛らわしい回答のグループです。読んだ後、ここですべての良いものを吸収することから数回の編集で答えが得られるかどうかわからないので、合計しようと思いました.

ここで述べた落とし穴を回避し、最も広く適用可能なソリューションを提供すると思われる拡張メソッドを次に示します。

public static string ReplaceCaseInsensitiveFind(this string str, string findMe,
    string newValue)
{
    return Regex.Replace(str,
        Regex.Escape(findMe),
        Regex.Replace(newValue, "\\$[0-9]+", @"$$$0"),
        RegexOptions.IgnoreCase);
}

そう...

残念ながら、 @HA の3 つすべてに対するコメントEscapeは正しくありません。初期値でnewValueある必要はありません。

注:ただし、 「キャプチャされた値」マーカーのように見えるものの一部である場合$は、挿入する新しい値で sをエスケープする必要があります。したがって、Regex.Replace 内の Regex.Replace の 3 つのドル記号 [原文ママ]。それがなければ、このようなものは壊れます...

"This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")

エラーは次のとおりです。

An unhandled exception of type 'System.ArgumentException' occurred in System.dll

Additional information: parsing "The\hisr\ is\ he\HISr\ fork,\ he\hIsr\ spoon,\ he\hisrsssssss\ knife\." - Unrecognized escape sequence \h.

教えてください、正規表現に慣れている人は、正規表現を使用するとエラーが回避されると感じていることは知っていますが、私はまだ文字列のバイトスニッフィングに部分的に取り組んでいます (ただし、Spolsky on encodingsを読んだ後でのみ)。重要なユースケースを対象としています。「安全でない正規表現」については、Crockford を少し思い出します。必要なものを許可する正規表現を (運が良ければ) 書き込んでしまうことがよくありますが、意図せずに多くのことを許可してしまいます (例えば$10、上記の newValue 正規表現で本当に有効な「キャプチャ値」文字列ですか?)。 . どちらの方法にも価値があり、どちらもさまざまな種類の意図しないエラーを助長します。多くの場合、複雑さを過小評価するのは簡単です。

その奇妙な$エスケープ (そして、置換値で期待していたRegex.Escapeようなキャプチャされた値のパターンをエスケープしなかった) は、しばらくの間私を怒らせました。$0プログラミングは難しい (c) 1842

于 2014-07-04T20:28:03.093 に答える
32

これが拡張メソッドです。どこで見つけたのかわからない。

public static class StringExtensions
{
    public static string Replace(this string originalString, string oldValue, string newValue, StringComparison comparisonType)
    {
        int startIndex = 0;
        while (true)
        {
            startIndex = originalString.IndexOf(oldValue, startIndex, comparisonType);
            if (startIndex == -1)
                break;

            originalString = originalString.Substring(0, startIndex) + newValue + originalString.Substring(startIndex + oldValue.Length);

            startIndex += newValue.Length;
        }

        return originalString;
    }

}
于 2011-07-20T00:35:14.680 に答える
32

最も簡単な方法は、.Net に同梱されており、.Net 1.0 から使用されている Replace メソッドを使用することです。

string res = Microsoft.VisualBasic.Strings.Replace(res, 
                                   "%PolicyAmount%", 
                                   "$0", 
                                   Compare: Microsoft.VisualBasic.CompareMethod.Text);

このメソッドを使用するには、参照を Microsoft.VisualBasic アセンブリに追加する必要があります。このアセンブリは .Net ランタイムの標準的な部分であり、余分なダウンロードや古いものとしてマークされたものではありません。

于 2010-08-23T19:47:25.920 に答える
3

Jeff Reddy の回答に基づいて、いくつかの最適化と検証を行います。

public static string Replace(string str, string oldValue, string newValue, StringComparison comparison)
{
    if (oldValue == null)
        throw new ArgumentNullException("oldValue");
    if (oldValue.Length == 0)
        throw new ArgumentException("String cannot be of zero length.", "oldValue");

    StringBuilder sb = null;

    int startIndex = 0;
    int foundIndex = str.IndexOf(oldValue, comparison);
    while (foundIndex != -1)
    {
        if (sb == null)
            sb = new StringBuilder(str.Length + (newValue != null ? Math.Max(0, 5 * (newValue.Length - oldValue.Length)) : 0));
        sb.Append(str, startIndex, foundIndex - startIndex);
        sb.Append(newValue);

        startIndex = foundIndex + oldValue.Length;
        foundIndex = str.IndexOf(oldValue, startIndex, comparison);
    }

    if (startIndex == 0)
        return str;
    sb.Append(str, startIndex, str.Length - startIndex);
    return sb.ToString();
}
于 2016-09-26T07:19:34.247 に答える
2

C. Dragon に似たバージョンですが、交換が 1 つだけ必要な場合:

int n = myText.IndexOf(oldValue, System.StringComparison.InvariantCultureIgnoreCase);
if (n >= 0)
{
    myText = myText.Substring(0, n)
        + newValue
        + myText.Substring(n + oldValue.Length);
}
于 2011-01-07T15:27:49.077 に答える
2

それぞれ .NET Core 2.0 または .NET Standard 2.1 以降、これは .NET ランタイムに組み込まれています [1]:

"hello world".Replace("World", "csharp", StringComparison.CurrentCultureIgnoreCase); // "hello csharp"

[1] https://docs.microsoft.com/en-us/dotnet/api/system.string.replace#System_String_Replace_System_String_System_String_System_StringComparison _

于 2020-08-08T12:03:09.260 に答える
0
Regex.Replace(strInput, strToken.Replace("$", "[$]"), strReplaceWith, RegexOptions.IgnoreCase);
于 2008-10-28T19:33:03.640 に答える
0

正規表現メソッドが機能するはずです。ただし、データベースの文字列を小文字にし、%variables% を小文字にしてから、データベースの小文字の文字列の位置と長さを見つけることもできます。文字列が小文字だからといって、文字列内の位置が変わるわけではないことに注意してください。

次に、逆のループを使用します(そうしないと、後でポイントが移動する場所の実行中のカウントを保持する必要があります)、データベースから小文字以外の文字列から %variables% を位置ごとに削除し、長さを変更し、置換値を挿入します。

于 2008-10-28T19:36:57.500 に答える