C# C中的大字符串正则表达式替换性能#
我在C#中遇到了正则表达式性能问题 我需要替换一个非常大的字符串(270k字符,不问为什么…)。正则表达式匹配大约3k次C# C中的大字符串正则表达式替换性能#,c#,regex,performance,replace,C#,Regex,Performance,Replace,我在C#中遇到了正则表达式性能问题 我需要替换一个非常大的字符串(270k字符,不问为什么…)。正则表达式匹配大约3k次 private static Regex emptyCSSRulesetRegex = new Regex(@"[^\};\{]+\{\s*\}", RegexOptions.Compiled | RegexOptions.Singleline); public string ReplaceEmptyCSSRulesets(string css) { return em
private static Regex emptyCSSRulesetRegex = new Regex(@"[^\};\{]+\{\s*\}", RegexOptions.Compiled | RegexOptions.Singleline);
public string ReplaceEmptyCSSRulesets(string css) {
return emptyCSSRulesetRegex.Replace(css, string.Empty);
}
传递给该方法的字符串如下所示:
.selector-with-statements{border:none;}.selector-without-statements{}.etc{}
目前,在C#中,替换过程需要1500ms,但当我在Javascript中执行完全相同的操作时,只需要100ms
我用于计时的Javascript代码:
console.time('reg replace');
myLargeString.replace(/[^\};\{]+\{\s*\}/g,'');
console.timeEnd('reg replace');
我还尝试通过以相反顺序循环匹配项并在StringBuilder中替换字符串来进行替换。那没用
在这种情况下,我对C#和Javascript之间的性能差异感到惊讶,我认为我做错了什么,但我想不出任何事情。我无法真正解释Javascript和C#(*)之间的时间差异。但是您可以尝试改进模式的性能(这会产生大量回溯):
private static Regex emptyCSSRulesetRegex=new Regex(@“(?[^};{]+)(?:{\s*}(?)”,RegexOptions.Compiled);
公共字符串替换EmptyCSRuleSets(字符串css){
返回emptyCSSRulesetRegex.Replace(css,@“${keep}”);
}
原始模式的一个问题是,当花括号不为空(或没有填充空格)时,正则表达式引擎将继续在打开花括号之前测试每个位置(结果始终相同)。例如:使用字符串abcd{1234}
您的模式将从a
开始测试,然后从b
开始测试
我建议的模式将消耗abcd
,即使后面没有空的花括号,因此不会测试bcd
的位置
abcd
在名为keep
的组中捕获,但当找到空的花括号时,捕获组将被空的捕获组覆盖
您可以了解这两种模式所需的步骤数(请检查调试器):
注意:如果将[^}{;]+
包含在一个原子组中,则可以改进原始模式。此更改会将所需的步数除以2(与原始模式相比),但即使如此,由于前面解释的原因,步数仍然很高
(*)javascript正则表达式引擎可能足够聪明,不会重试所有这些位置,但这只是一个假设。我认为用于JS和C的正则表达式引擎是不同的。你不应该跨语言比较特性。我不确定C是否正确,但在Java中,正则表达式的创建(当你进行
匹配时)(
)它本身是一个耗时的过程。它涉及同步和其他耗时的内容。请尝试将\s
更改为[\f\n\r\t\v\u00A0\u2028\u2029]
或使用RegexOptions.ECMAScript
。在JS和C#中处理字符类的方式上存在差异,我同意,但差异很大……因此这可能是一个信号,表明我在C#中做错了什么。我正试图找出确切的原因。看看@stribizev你认为正则表达式是问题所在吗?That与javascript正则表达式的执行时间不一致。但是我做了一个只匹配而不替换的测试,这在C#中很快。谢谢!您的正则表达式似乎可以工作。我将在javascript正则表达式中尝试also@WillemdeWit:您不能在javascript中使用相同的模式,因为它不支持命名捕获,但您可以编写一些东西使用回调函数作为替换类似:str.replace(/[^};{]+({\s*})/g,函数(m,g1){return(g1)''':m;});
结果也比以前快了10倍。比以前快了10倍?或者比JS@CasimiretHippolyte中的前一个正则表达式快了10倍-你能带上“原始模式”和“新模式”吗答案中的正则表达式-外部链接不受欢迎,因为外部站点可能会更改,从而破坏SO社区的宝贵答案。除了在答案中显示正则表达式外,您当然可以拥有该链接。
private static Regex emptyCSSRulesetRegex = new Regex(@"(?<keep>[^};{]+)(?:{\s*}(?<keep>))?", RegexOptions.Compiled);
public string ReplaceEmptyCSSRulesets(string css) {
return emptyCSSRulesetRegex.Replace(css, @"${keep}");
}