【问题标题】:How to rewrite Regex.Replace (due to async api)如何重写 Regex.Replace(由于 async api)
【发布时间】:2015-10-09 14:45:34
【问题描述】:

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

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&lt;string&gt; GetReplacementAsync(string parameter) ReplaceParameterEvaluator 函数无法与 MatchEvaluator 委托兼容。

由于这必须在网络服务器上运行并且不会导致死锁,我不能使用任何肮脏的异步同步黑客,例如:(使用 .Result)var replacedQuery = Regex.Replace(query, @"(?&lt;parameter&gt;\|\w+\|)", match =&gt; ReplaceParameterEvaluatorAsync(match).Result, RegexOptions.ExplicitCapture);

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

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

【问题讨论】:

  • 不要使用GetReplacementAsync 或使用“hacks”。这里没有优雅的解决方案。
  • 发布后我发现osdn.jp/projects/opentween/scm/git/open-tween/blobs/master/… - 其中包含 RegexAsync.ReplaceAsync 的简单实现。但它不支持捕获组。也许在我的情况下可以使用类似的方法?
  • 好像先匹配一切,然后异步查找替换,然后替换一切。它使用了两次正则表达式,但是是的,这可能是可能的。
  • 没有 Regex.ReplaceAsync 函数,因为字符串替换不是 I/O 绑定操作,公开异步 API 没有意义。

标签: c# regex async-await


【解决方案1】:

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

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 绑定操作,这自然不是异步的。

【讨论】:

  • 您甚至可以并行化所有对replacementFn 的调用,然后在最后构建字符串。
  • 自从我上次使用正则表达式类已经有好几年了...正如您在原始代码中看到的那样,我正在使用 Regex.Replace (静态版本) - 是否可以更改我的代码改为使用正则表达式实例?
  • new Regex(@"(?&lt;parameter&gt;\|\w+\|)", RegexOptions.ExplicitCapture).ReplaceAsync(...)
  • @Rawling 我会小心的。如果replacementFn 不是线程安全的怎么办?
  • 坦克!我对 regex 不是 cpu-bound 没有任何问题。 我的功能,然而。 - 你给了一个很好的解决方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多