0

有谁知道哪个更适合潜在的字符串替换?

如果我有一系列不同长度的字符串,其中一些字符串可能需要特殊替换编码的十六进制值(例如 = 0A、%20... 等)

每个字符串的“替换”(可能有多个)将由正则表达式处理,以检测适当的转义十六进制值

哪个效率更高?

  1. 只需在集合中的每个字符串上运行替换,通过蛮力确保完成所有需要的替换

  2. 如果需要替换,则执行测试,并且在需要它的字符串上运行替换。

我在 C# 中工作。

更新

来自答案和评论的一些附加信息。

这主要用于从 QR 码加载的 VCARD 处理

我目前有一个正则表达式,它使用捕获组从 VCARD 中的每个 KEY;PARAMETERS:VALUE 获取 KEY、PARAMETERS 和 VALUE。

由于我支持 v 2.1 和 3.0,因此编码和行折叠非常不同,所以我需要在解码之前知道版本。

现在运行整个正则表达式对我来说没有意义只是为了获取版本并将适当的替换应用于整个 vcard 文本块然后重新运行正则表达式。

对我来说,加载我的捕获组然后获取版本并在每场比赛中进行适当的解码替换更有意义

4

4 回答 4

1

当您只是 Replace 时,它​​会在没有匹配时执行稍慢,因为 Replace 会进行额外的检查(例如)

if (replacement == null)
{
    throw new ArgumentNullException("replacement");
}

如果没有找到匹配项,Regex.Replace 会返回输入,因此这里没有内存问题。

Match match = regex.Match(input, startat);
if (!match.Success)
{
    return input;
}

当有匹配时, regex.Match 会在您执行此操作时触发两次,而在 replace 执行此操作时会再次触发。这意味着检查和替换将执行较慢。

所以你的结果将基于

  • 你期待很多比赛还是很多失误?
  • 当有匹配项时,Regex.Match将运行两次这一事实如何超过额外的参数检查?我的猜测是它可能会。
于 2012-06-01T22:42:29.513 回答
0

您可以使用带有前瞻性检查的非常专业的词法分析器的东西,例如

outputBuffer := new StringBuilder
index := 0
max := input.Length
while index < max
    if input[ index ] == '%'
    && IsHexDigit( input[ index + 1 ] )
    && IsHexDigit( input[ index + 2 ] )
        outputBuffer.Append( ( char )int.Parse( input.Substring( index + 1, 2 )
        index += 3
        continue
    else
        outputBuffer.Append( input[ index ] )
        index ++;
        continue
于 2012-06-02T00:23:10.053 回答
0

如果您使用字符串替换,使用StringBuilder.Replace可能比使用 string.Replace 更好。(替换时不会创建很多临时字符串......)

于 2012-06-02T05:42:06.630 回答
0

(代表问题作者发布)

从一些插话的好人那里得到一些启发,我设法隔离并测试了有问题的代码。

在这两种情况下,我都有一个解析器正则表达式来处理分解电子卡的每一“行”,以及一个解码正则表达式来处理捕获任何编码的十六进制数字。

我突然想到,无论我是否使用 string.Replace,我仍然必须依靠 Decode Regex 来获取潜在的替换十六进制代码。

我经历了几个不同的场景,看看数字是否会改变;包括:将 Regex MatchCollection 转换为 Dictionary 以消除 Match 对象的复杂性,并将 Decoding 正则表达式投影到具有旧字符串值和新字符串值的不同简单匿名对象的集合中。替换调用

最后,无论我如何使用 String.Replace 按摩测试,它都接近但总是比让解码的正则表达式做它的替换事情慢。

最接近的是大约 12% 的速度差异。

最后,对于那些好奇的人来说,这最终成为了获胜的代码块

    var ParsedCollection = Parser.Matches(UnfoldedEncodeString).Cast<Match>().Select(m => new
    {
      Field = m.Groups["FIELD"].Value,
      Params = m.Groups["PARAM"].Captures.Cast<Capture>().Select(c => c.Value),
      Encoding = m.Groups["ENCODING"].Value,
      Content = m.Groups["ENCODING"].Value.FirstOrDefault == 'Q' ? QuotePrintableDecodingParser.Replace(m.Groups["CONTENT"].Value, me => Convert.ToChar(Convert.ToInt32(me.Groups["HEX"].Value, 16)).ToString()) : m.Groups["CONTENT"].Value,
      Base64Content = ((m.Groups["ENCODING"].Value.FirstOrDefault() == 'B') ? Convert.FromBase64String(m.Groups["CONTENT"].Value.Trim()) : null)
    });

一口气给了我我需要的一切。所有字段、它们的值、任何参数以及解码后的两种最常见的编码都投射到一个很好打包的匿名对象中。

从好的方面来说,从字符串到解析和解码的匿名对象只有 1000 多纳秒(感谢 LINQ 和扩展方法)(基于 100,000 次测试和大约 4,000 长度的 VCARD)。

于 2017-11-01T21:01:05.613 回答