8

パフォーマンスの良い方法で、文字列内の名前付きパラメーターをコードの名前付きパラメーター、たとえば私の文字列に置き換えたいです。

"Hi {name}, do you like milk?"

{name} をコード、正規表現で置き換えるにはどうすればよいですか? 高価に?どの方法をお勧めしますか?

NHibernates HQL の例で :my_param をユーザー定義の値に置き換えるにはどうすればよいですか? または、私が好む ASP.NET (MVC) ルーティングでは、"{controller}/{action}", new { controller = "Hello", ... }?

4

9 に答える 9

20

正規表現が高すぎることを確認しましたか?

正規表現のコストは非常に誇張されています。このような単純なパターンの場合、パフォーマンスは非常に優れていますが、実際には直接の検索と置換よりもわずかに劣るだけです。Compiledまた、正規表現を作成するときにフラグを試しましたか?

とはいえ、最も単純な方法、つまりを使用することはできませんReplaceか?

string varname = "name";
string pattern = "{" + varname + "}";
Console.WriteLine("Hi {name}".Replace(pattern, "Mike"));
于 2008-12-18T21:25:12.870 に答える
14

正規表現は確かに実行可能なオプションであり、特にMatchEvaluator:

    Regex re = new Regex(@"\{(\w*?)\}", RegexOptions.Compiled); // store this...

    string input = "Hi {name}, do you like {food}?";

    Dictionary<string, string> vals = new Dictionary<string, string>();
    vals.Add("name", "Fred");
    vals.Add("food", "milk");

    string q = re.Replace(input, delegate(Match match)
    {
        string key = match.Groups[1].Value;
        return vals[key];
    });
于 2008-12-18T21:26:50.073 に答える
4

次のように、辞書に置換があるとします。

    var  replacements = new Dictionary<string, string>();
    replacements["name"] = "Mike";
    replacements["age"]= "20";

次に、正規表現は非常に単純になります。

Regex regex = new Regex(@"\{(?<key>\w+)\}");
    string formattext = "{name} is {age} years old";
    string newStr = regex.Replace(formattext, 
            match=>replacements[match.Groups[1].Captures[0].Value]);
于 2008-12-18T21:45:19.863 に答える
2

これについて考えた後、私が実際に望んでいたことは、String.Format() が引数として IDictionary を取り、インデックスの代わりに名前を使用してテンプレートを記述できることであることに気付きました。

多くの可能なキー/値を持つ文字列置換の場合、インデックス番号は判読できない文字列テンプレートになります。場合によっては、どのアイテムがどの番号を持つのかさえわからない可能性があるため、次の拡張を思いつきました:

https://gist.github.com/896724

基本的に、これにより、数値の代わりに名前を使用して文字列テンプレートを使用し、配列の代わりに辞書を使用して、String.Format() の他のすべての優れた機能を使用できるようになり、必要に応じてカスタム IFormatProvider を使用できるようになります。精度、長さなど、すべての通常の書式設定構文の使用。

String.Formatのリファレンス マテリアルで提供されているは、多くの番号付きアイテムを含むテンプレートが完全に判読不能になる方法の優れた例です。この例を移植して、この新しい拡張メソッドを使用すると、次のようになります。

var replacements = new Dictionary<String, object>()
                       {
                           { "date1", new DateTime(2009, 7, 1) },
                           { "hiTime", new TimeSpan(14, 17, 32) },
                           { "hiTemp", 62.1m },
                           { "loTime", new TimeSpan(3, 16, 10) },
                           { "loTemp", 54.8m }
                       };

var template =
    "Temperature on {date1:d}:\n{hiTime,11}: {hiTemp} degrees (hi)\n{loTime,11}: {loTemp} degrees (lo)";

var result = template.Subtitute(replacements);

誰かが指摘したように、あなたが書いているものを高度に最適化する必要がある場合は、このようなものを使用しないでください.ループで何百万もの文字列をこのようにフォーマットする必要がある場合、メモリとパフォーマンスのオーバーヘッドが大きくなる可能性があります.

一方、読みやすく、保守しやすいコードを書くことに関心がある場合、そしてたとえば一連のデータベース操作を行っている場合、大まかに言えば、この関数によって大きなオーバーヘッドが追加されることはありません。

...

便宜上、辞書の代わりに匿名オブジェクトを受け入れるメソッドを追加しようとしました。

public static String Substitute(this String template, object obj)
{
    return Substitute(
        template,
        obj.GetType().GetProperties().ToDictionary(p => p.Name, p => p.GetValue(obj, null))
    );
}

なんらかの理由で、これは機能しません。new { name: "value" }拡張メソッドのような匿名オブジェクトを渡すと、そのメソッドの IDictionary バージョンが最適であるというコンパイル時のエラー メッセージが表示されます。それを修正する方法がわからない。(誰でも?)

于 2011-03-31T17:06:07.767 に答える
1

どうですか

stringVar = "Hello, {0}. How are you doing?";
arg1 = "John";    // or args[0]
String.Format(stringVar, arg1)

{x} をインクリメントし、別のパラメーターを Format() メソッドに追加するだけで、複数の引数を持つこともできます。違いはわかりませんが、「string」と「String」の両方にこのメソッドがあります。

于 2010-02-03T17:41:05.957 に答える
0

または、すべての置換値がディクショナリ obj に格納されている場合は、Linq でこれを試してください。

例えば:

Dictionary<string,string> dict = new Dictionary<string,string>();
dict.add("replace1","newVal1");
dict.add("replace2","newVal2");
dict.add("replace3","newVal3");

var newstr = dict.Aggregate(str, (current, value) => current.Replace(value.Key, value.Value));

dictは、検索と置換のペアで定義された Dictionary オブジェクトです。 strは、いくつかの置換を行う必要がある文字列です。

于 2011-10-31T18:12:35.513 に答える
0

コンパイルされた正規表現は、特に置換するトークンが多数ある場合にうまくいく可能性があります。それらがほんの一握りで、パフォーマンスが重要な場合は、インデックスでトークンを見つけて、文字列関数を使用して置き換えるだけです。信じられないかもしれませんが、これは正規表現よりも高速です。

于 2008-12-18T21:26:06.517 に答える
0

StringTemplate を使用してみてください。それよりもはるかに強力ですが、完璧に機能します。

于 2009-03-29T01:15:14.683 に答える
0

私は mindplay.dk ソリューションに行きます...非常にうまく機能します。

また、わずかな変更を加えて、「Hi {name}, do you like {0}?」のようなテンプレートのテンプレートをサポートし、{name} を置き換えますが、{0} は保持します:

指定されたソース ( https://gist.github.com/896724 ) で、次のように置き換えます。

        var format = Pattern.Replace(
            template,
            match =>
                {
                    var name = match.Groups[1].Captures[0].Value;

                    if (!int.TryParse(name, out parsedInt))
                    {
                        if (!map.ContainsKey(name))
                        {
                            map[name] = map.Count;
                            list.Add(dictionary.ContainsKey(name) ? dictionary[name] : null);
                        }

                        return "{" + map[name] + match.Groups[2].Captures[0].Value + "}";
                    }
                    else return "{{" + name + "}}";
                }
            );

さらに、長さ ({name,30}) とフォーマット指定子、または両方の組み合わせをサポートします。

于 2011-11-09T16:05:44.853 に答える