【发布时间】:2013-10-18 03:15:21
【问题描述】:
我有一个在http://gskinner.com/RegExr/ 和http://regexhero.net/tester/ 上运行良好的正则表达式,即.net。但是它在我的 .net v4.5 代码中超时(1h+)。
(?<OuterDescription>[ \t]*--[ \t]+Description:[ \t]+(?!\<Description)(?<Description>\S[^\r\n]{1,})((\r\n|\r|\n)(?![ \t]*--[ \t]*Modified)[^\r\n]*)*)
带有样本数据:
-- ========================================================================================================
-- Author: A Name
-- Create date: 11/26/2012
-- Description: A description
-- A multiline description
-------------------------------------- Group Name -----------------------------------------
-- More details
-- More details
--
-- Modified: 01/7/2012 - Some reason
-- Modified: 12/7/2012 - Some other reason
-- ========================================================================================================
我的代码是这样的
var isMatch = new Regex(pattern, RegexOptions.None, TimeSpan.FromMinutes(1)).IsMatch(_fileText);
希望 OuterDescription 从 -- Description 捕获到 -- Modified 之前
我已将其范围缩小到接近尾声的[^\r\n]*。我不知道如何在 c# 中解决此问题以不超时
编辑:
感谢您的讨论和回答。它有助于将超时从描述中移出。不幸的是,我仍然遇到问题。这就是我目前所拥有的
[ \t]*--[ \t]+={3,}
(\r\n|\n|\r)
(?<OuterAuthor>[ \t]*--[ \t]+
Author:[ \t]+
(?!\<Author)
(?<Author>\S[^\r\n]+))
(\r\n|\n|\r)
(?<OuterCreateDate>[ \t]*--[ \t]+
Create\ [Dd]ate:[ \t]+
(?!\<Create)
(?<CreateDate>\S[^\r\n]{1,}))
(\r\n|\n|\r)
(?<OuterDescription>[ \t]*--[ \t]+
Description:[ \t]+
(?!\<Description)
(?<Description>\S[^\r\n]+)
(?<MultilineDescription>((\r\n|\r|\n)|[^\r\n]*)*?)
(?=(
[ \t]*--[ \t]*Modified)|(
[ \t]*--[ \t]*={3,})
))
这很好,但是一旦我在此之后添加一些内容,它就会超时。
对不起,我没有首先提到这一点,我认为一点点贪婪的星星变化将是我的全部问题。为了了解最终图片,我有一个 isAdded 布尔值,它将确定我是否检查修改的行(与描述相同),然后以页眉/页脚结束。像这样
var entireCommentHeaderNamedGroupsRegex = headerFooterRegex + newlineRegex
+ authorRegex + newlineRegex
+ createDateRegex + newlineRegex
+ descriptionRegex + newlineRegex
+ (_isAdded ? modifiedRegex + newlineRegex : "")
+ headerFooterRegex;
未修改时的更多示例数据:
-- =============================================
-- Author: Garrett Carson
-- Create date: 10/4/2013
-- Description: This is a test
-- =============================================
CREATE PROCEDURE dbo.ThisIsATest
AS
BEGIN
PRINT 'This is a test'
END
另外,正如 cmets 中提到的,我对正则表达式(在这个规模上)相当陌生,所以如果这实际上不是灾难性的回溯,请原谅我的术语。
编辑 2
作为最后的编辑,我最终选择了一个穷人的 fsm
string currentState = "LookForAuthor"
foreach (var line in lines) {
switch currentState {
case "LookForAuthor" : {
... use author regex ... save to author variable ...
if(found) currentState = "LookForCreateDate"
else throw new InvalidCommentException();
}
case "LookForCreateDate": {
... use createDate regex ... save to createDate variable ...
...
}
...
}
}
if (!_isAdded && !(currentState == "Modified-FirstLine" || currentState == "Modified-MoreLines")) {
throw new InvalidCommentException();
}
然后我重新考虑使用枚举。逐行应用的一口大小的正则表达式不再导致超时。
【问题讨论】:
-
据我所知,正则表达式永远不会回溯...您确定超时是由于正则表达式引起的吗?也许您只是在分析一个巨大的文件?
-
@CommuSoft 你错了。不管怎样,Garret,你期望得到什么输出,也许我可以用一个更好的正则表达式来代替你的问题?
-
我认为您需要指定 RegexOptions.Multiline,因为您使用 ^ 作为行首。
-
加勒特,我怀疑您发布的那一小段示例文本会导致灾难性的回溯。如果我们没有实际导致问题的输入数据,我们应该如何调试您的正则表达式? :)
-
@Sniffer:根据我在编译器方面的工作,我知道正则表达式被编译为非确定性有限自动机,然后将此类自动机修改为确定性的自动机(使用动态编程),在 O( n)。所有不能在线性时间内运行的东西,都不应该被称为正则表达式,并且可以做的不仅仅是有限状态机......