2009-02-04 32 views
3

我有一个超过一百万行的文件。更有效的正则表达式还是替代方法?

{<uri::rdfserver#null> <uri::d41d8cd98f00b204e9800998ecf8427e> <uri::TickerDailyPriceVolume> "693702"^^<xsd:long>} 
{<uri::rdfserver#null> <uri::d41d8cd98f00b204e9800998ecf8427e> <uri::TickerDailyPriceId> <uri::20fb8f7d-30ef-dd11-a78d-001f29e570a8>} 

每一行都是一条语句。

struct Statement 
    string C; 
    string S; 
    string P; 
    string O; 
    string T; 

目前我使用一个while循环的TextReader和解析使用正则表达式的每一行:

Regex lineParse = new Regex(@"[^<|\""]*\w[^>\""]*", RegexOptions.Singleline | RegexOptions.Compiled); 

这需要很长一段时间做这个分析,我希望有人能我更有效的解析策略。

有些线路有5分配衬有的4.这里是每行是如何解析:

{<uri::rdfserver#null> <uri::d41d8cd98f00b204e9800998ecf8427e> <uri::TickerDailyPriceVolume> "693702"^^<xsd:long>} 

Statement() 
    C = uri::rdfserver#null 
    S = uri::d41d8cd98f00b204e9800998ecf8427e 
    P = uri::TickerDailyPriceVolume 
    O = 693702 
    T = xsd:long 

{<uri::rdfserver#null> <uri::d41d8cd98f00b204e9800998ecf8427e> <uri::TickerDailyPriceId> <uri::20fb8f7d-30ef-dd11-a78d-001f29e570a8>} 

Statement() 
    C = uri::rdfserver#null 
    S = uri::d41d8cd98f00b204e9800998ecf8427e 
    P = uri::TickerDailyPriceId 
    O = uri::20fb8f7d-30ef-dd11-a78d-001f29e570a8 

从注释附加信息:“可怜的表现我所看到的实际上是因为条件断点我没有任何改变,但是如果有人有任何改进的想法,我会感兴趣的“-Eric Sc​​hoonover

+0

我看到的糟糕的性能实际上是由于我在代码中设置了条件断点。没有这个断点,一切都很快。如果有人有任何改进的想法,我会感兴趣:) – 2009-02-04 23:33:03

+0

你可能会添加该信息到你的文章,所以人们知道你不再寻找速度。 – 2009-02-04 23:38:16

+0

我仍然在寻找速度,只是我发布的正则表达式不一定像我想的那样慢。 – 2009-02-05 00:10:19

回答

18

最快的(如下图所示)是一个简单的字符串拆分:

line.Split(new char[] { '{', '<', '>', '}', ' ', '^', '"' }, 
      StringSplitOptions.RemoveEmptyEntries); 

的最快是锚定的正则表达式(难看):

Regex lineParse 
    = new Regex(@"^\{(<([^>]+)>\s*){3,4}(""([^""]+)""\^\^<([^>]+)>\s*)?\}$", 
       RegexOptions.Compiled); 
Match m = lineParse.Match(line); 
if (m.Groups[2].Captures.Count == 3) 
{ 
    Data data = new Data { C = m.Groups[2].Captures[0].Value, 
     S = m.Groups[2].Captures[1].Value, P = m.Groups[2].Captures[2].Value, 
     O = m.Groups[4].Value, T = m.Groups[5].Value }; 
} else { 
    Data data = new Data { C = m.Groups[2].Captures[0].Value, 
     S = m.Groups[2].Captures[1].Value, P = m.Groups[2].Captures[2].Value, 
     O = m.Groups[2].Captures[3].Value, T = String.Empty }; 
} 

计时为1M行随机数据(String.Split作为基线):

Method    #1 Wall (Diff)  #2 Wall (Diff) 
------------------------------------------------------------ 
line.Split    3.6s (1.00x)   3.1s (1.00x) 
myRegex.Match    5.1s (1.43x)   3.3s (1.10x) 
itDependsRegex.Matches 6.8s (1.85x)   4.4s (1.44x) 
stateMachine    8.4s (2.34x)   5.6s (1.82x) 
alanM.Matches    9.1s (2.52x)   7.8s (2.56x) 
yourRegex.Matches  18.3s (5.06x)  12.1s (1.82x) 

更新以包括@ AlanM和@itdepends正则表达式。看来Regex.Matches比Regex.Match慢,但是,您给解析器的上下文线索越多,执行得越好。 @AlanM使用的单个负面字符类最容易阅读,但比最神秘的(我的)要慢。为最简单的正则表达式创造最快的时间。好吧,虽然我认为编写一个状态机来分析这条线会很疯狂,但实际上它并没有表现得很差......对于这个建议,我很赞赏@RexM。我还在家中添加了我在Q6600上的时间(#2)v。工作中的旧至强(#1)。

2

一些测试后,我想出了:

@"<(?<capture>[^>]+)>|""(?<capture>[^""]+)""" 

值需要与match.Groups [1] .value的被acessed。

在我不科学的测试中,它比原始问题中的速度快75-80%左右。

比赛VS匹配

在生产中我通常使用匹配,但用于匹配的上方。我从来没有真正考虑对性能的影响所以做了一个小测试,所以用完全一样正则表达式

for(Match match = regex.Match(input); match.Success; match = match.NextMatch()) 
// min 5.01 sec 
// max 5.15 sec 

foreach(Match match in regex.Matches(input)) 
// min 5.66 sec 
// max 6.07 sec 

所以比赛肯定可以比匹配更快。

6

有时状态机比正则表达式快很多。

1

据我所见,到目前为止提供的正则表达式比他们需要的要复杂得多。如果@sixlettervariables'拆分方法工作,比赛应与此正则表达式的工作:

@"[^{}<> ^""]+" 

但我仍然期待String.Split方法要快。