C# 列出输入字符串的替换值 - 最快的方法

C# List replacement values for input string - Quickest way

我有一个 MyObj 的静态列表,它是从 json 文件动态填充的。

public class MyObj
{
    public string OriginalValue { get; set; } = "";
    public string ReplacementValue { get; set; } = "";
}

为了这个问题,我将用 foo 值填充列表。

public static List<MyObj> ReplacementValues = new MyObj[]
{
    new MyObj() { OriginalValue = "{a}",  ReplacementValue = "Queen" },
    new MyObj() { OriginalValue = "{m}",  ReplacementValue = "Cersei" },
    new MyObj() { OriginalValue = "{s1}", ReplacementValue = "Khaleesi" },
    new MyObj() { OriginalValue = "{p}",  ReplacementValue = "Harry" },
    ...
    new MyObj() { OriginalValue = "{_2_29sa}",  ReplacementValue = "229Z" }
}.ToList();

然后我有一个输入字符串(可以是任何东西,相同 {x} 值的倍数,30 倍):

var inputstring = "The Khal is looking for a {a}, her name must not be {m}. He found one called {s1}. {p} Potter {p}{p}{p}{p}{p}{p}";

有什么方法可以快速遍历这些值,用替换值替换字符串中的值。

我可以使用 indexOf 等执行 foreach 循环并遍历静态列表,但列表可能会变得很大,假设有 15000 个条目。我知道这听起来不多,但替换应该接近实时,如果输入字符串中有 400 倍的相同值,最终可能会在 15k 列表中循环很多次。

是否有更快的 lambda 或 Regex 方法可以将字符串中的值快速替换为查找列表中的值?

我认为最简单的方法是使用 String.Replaceforeach 循环。

foreach(var r in ReplacementValues)
{
      inputString.Replace(r.OriginalValue, r.ReplacementValue);
}

或者你可以简化这个(注意这样效率较低):

ReplacementValues.ForEach(r => inputList.Replace(r.OriginalValue, r.ReplacementValue);

我建议带 MatchEvaluator 代表的 Regex.Replace 是最佳选择:

var dictReplacement = ReplacementValues.ToDictionary(rv => rv.OriginalValue, rv => rv.ReplacementValue);

var ans = Regex.Replace(inputstring, @"\{.+?\}", m => dictReplacement.ContainsKey(m.Value) ? dictReplacement[m.Value] : m.Value);

如果你有 C# 7.0,你可以改用这个:

var ans = Regex.Replace(inputstring, @"\{.+?\}", m => dictReplacement.TryGetValue(m.Value, out var subst) ? subst : m.Value);

考虑到您的列表可能包含如此多不同的对象,我认为最好扫描更短的输入字符串,然后只替换您在其中找到的标签。

您可以将其与字典的快速检索时间相结合

Dictionary<string, string> test = new Dictionary<string, string>()
{
    {"{a}", "the new hero"},
    {"{b}", "of the new era"}
};
.....

string input = GetInputString();
int posStart = 0;
while ((posStart = input.IndexOf("{", posStart)) != -1)
{
    int posEnd = replacements.IndexOf("}", posStart+1);
    if(posEnd == -1)
        break;

    string sub = input.Substring(posStart, posEnd+1-posStart);
    if(test.ContainsKey(sub))
        input = input.Replace(sub, test[sub]);
    posStart++;
}
Console.WriteLine(input);