我的软件允许用户使用regexp来准备文件。我正在添加一个带有常用表达式的默认regexp库,可以重复使用它来准备各种格式。 一个常见的任务是删除文件特定部分中的crlf,但不删除其他部分。例如,这个:
<TU>Lorem
Ipsum</TU>
<SOURCE>This is a sentence
that should not contain
any line break.
</SOURCE>
应该成为:
<TU>Lorem
Ipsum</TU>
<SOURCE>This is a sentence that should not contain any line break.
</SOURCE>
我有一个rexep可以很好地完成工作:
(?(?<=<SOURCE>(?:(?!</?SOURCE>).)*)(\r\n))
问题是它处理密集,文件高于500kb,可能需要30秒以上。 (编译正则表达式,在这种情况下,未编译的速度要慢得多)
这不是一个大问题,但我想知道是否有更好的方法来与Regex实现相同的结果。
提前感谢您的建议。
答案 0 :(得分:2)
“编译”正则表达式只是意味着将其从Deterministic Finite Automaton转换为Non-deterministic Finite Automaton。它并不像你期望的那样“编译成机器代码”。
NFA通常比相应的DFA小,可以有效地执行更多空间。每个DFA至少有一个等效的NFA,反之亦然。但是,Perl Compatible Regular Expressions不是actually Regular。所以我不知道他们被转换成NFA,或者“编译”只是另一种形式的词法分析,一次不需要再做。
根据Russ Cox,PCRE很慢,部分原因是它们不规律,上面的表达非常规律。
哦,如果您尝试使用regexp识别嵌套标签,请不要。使用真正的(X|HT)?ML
解析器。你真的不希望the pony来
答案 1 :(得分:2)
我会在正则表达式中添加一个负前瞻断言,以确保您实际上可以在当前位置匹配\r\n
。否则,引擎必须对整个文件中的每个字符执行整个lookbehind(任意大小引导),然后才发现没有回车符。
(?=\r\n)(?(?<=<SOURCE>(?:(?!</?SOURCE>).)*)(\r\n))
应该快得多。至少在RegexBuddy中,正则表达式引擎需要更少的步骤才能完成匹配。如果它不在.NET中,我不知道为什么。也许条件正则表达式效率不高(我必须承认,起初我没有认出它,并认为你的正则表达式中存在语法错误)。我认为在这种情况下你不需要条件正则表达式。 <怎么样
\r\n(?<=<SOURCE>(?:(?!</?SOURCE>).)*)
这更快吗?我假设您正在使用RegexOptions.Singleline
来编译正则表达式。
如果没有,那么,<SOURCE>
块内可能会有非常多的回车和许多其他字符,并且任意大小的后视需要很长时间。然后我的另一个建议是分开任务:
<SOURCE>
块<SOURCE>
块答案 2 :(得分:2)
试试这个:
\r\n(?=(?>[^<>]*(?><(?!/?SOURCE>)[^<>]*)*)</SOURCE>)
首先匹配\r\n
,然后使用前瞻来查看匹配是否在<SOURCE>
和</SOURCE>
之间。它通过查找</SOURCE>
来实现,但如果找到<SOURCE>
则首先失败。原子组阻止它保存回溯所需的状态信息,因为传递或失败,从不需要回溯。