2009-02-04 37 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方法要快。