如何重写Regex.Replace(由于async api)

时间:2015-10-08 11:06:18

标签: c# regex async-await

我有一个函数ReplaceParameters,它使用Regex.Replace替换字符串中的值。这一直工作正常,但现在获取replacement-string的api已变为async-only。这是当前代码的重复:

public static string ReplaceParameters(string query)
{
    var result = Regex.Replace(query, @"(?<parameter>\|\w+\|)", ReplaceParameterEvaluator,
                                         RegexOptions.ExplicitCapture);

    return result;
}

private static string ReplaceParameterEvaluator(Match parameterMatch)
{
    var parameter = parameterMatch.Groups["parameter"].Value;
    return GetReplacement(parameter);
}

private static string GetReplacement(string parameter)
{
    //...
}

由于(新)GetReplacement函数现在返回一个Task而不是字符串:private static async Task<string> GetReplacementAsync(string parameter),因此ReplaceParameterEvaluator函数不能与MatchEvaluator委托兼容。

这必须在Web服务器上运行并且不会导致死锁,我无法使用任何脏的异步到同步黑客,例如:(使用.Result)var replacedQuery = Regex.Replace(query, @"(?<parameter>\|\w+\|)", match => ReplaceParameterEvaluatorAsync(match).Result, RegexOptions.ExplicitCapture);

是否可以重写函数以查找所有文本,然后替换它们?可以用某种方式使用Regex.Matches吗?

(说真的,为什么没有Regex.ReplaceAsync函数?)

1 个答案:

答案 0 :(得分:7)

为此构建自己的扩展方法非常简单:

public static async Task<string> ReplaceAsync(this Regex regex, string input, Func<Match, Task<string>> replacementFn)
{
    var sb = new StringBuilder();
    var lastIndex = 0;

    foreach (Match match in regex.Matches(input))
    {
        sb.Append(input, lastIndex, match.Index - lastIndex)
          .Append(await replacementFn(match).ConfigureAwait(false));

        lastIndex = match.Index + match.Length;
    }

    sb.Append(input, lastIndex, input.Length - lastIndex);
    return sb.ToString();
}

这很简单:

  • 将不匹配的文本块原样复制到StringBuilder
  • 追加文本匹配的回调函数的结果

这只是调用异步回调的便捷方法。它不在API中,因为正则表达式匹配和替换是一个CPU绑定操作,这自然不是异步的。