2012-04-15 102 views
6

這是從some other question的討論衍生出來的。解析無字符串拆分

假設我必須解析大量很長的字符串。每個字符串都包含一個由空格分隔的double(當然用文本表示)的序列。我需要將double解析爲List<double>

標準解析技術(使用string.Split + double.TryParse)似乎很慢:對於每個數字我們需要分配一個字符串。

我試圖使它成爲類似於C的方式:計算包含數字的子串的開始和結束的索引,並將其解析爲「到位」,而不創建額外的字符串。 (見http://ideone.com/Op6h0,如下圖所示的相關部分。)

int startIdx, endIdx = 0; 
while(true) 
{ 
    startIdx = endIdx; 
    // no find_first_not_of in C# 
    while (startIdx < s.Length && s[startIdx] == ' ') startIdx++; 
    if (startIdx == s.Length) break; 
    endIdx = s.IndexOf(' ', startIdx); 
    if (endIdx == -1) endIdx = s.Length; 
    // how to extract a double here? 
} 

還有就是string.IndexOf過載,只有一個給定的字符串中進行搜索,但我沒能找到解析從子雙重方法,實際上並沒有提取那子串第一。

有沒有人有想法?

+5

你有沒有證明了這其實是一個瓶頸?我不知道*以任何方式做副手,但我肯定希望有一些證據表明這是微型優化之前的問題。 – 2012-04-15 11:22:29

+0

@Jon:不是。這個問題是基於鏈接問題的討論(http://stackoverflow.com/questions/10053449/extract-numbers-from-string)。對不起。 – Vlad 2012-04-15 11:23:13

+0

夠公平的。我懷疑手寫的解析程序會比BCL團隊提出的大概經過優化的大量體驗方法要慢:) – 2012-04-15 11:25:23

回答

7

沒有託管的API來解析子字符串中的一個double。我的猜測是,與double.Parse中的所有浮點運算相比,分配字符串將是微不足道的。

無論如何,您可以通過創建一個長度爲100且僅包含空格的「緩衝區」字符串來保存分配。然後,對於要分析的每個字符串,使用不安全代碼將字符複製到此緩衝區字符串中。用空格填充緩衝區字符串。而對於解析,您可以使用NumberStyles.AllowTrailingWhite,這將導致尾隨空白被忽略。

獲得一個指向字符串實際上是完全支持的操作:

string l_pos = new string(' ', 100); //don't write to a shared string! 
    unsafe 
    { 
     fixed (char* l_pSrc = l_pos) 
     {    
       // do some work 
     } 
    } 

C#有特殊的語法爲字符串綁定到一個char *。

如果你想這樣做真快
+0

我的理解是否正確:你的意思是修改一個假定不可變的'System.String'與不安全的代碼? – Vlad 2012-04-15 12:23:20

+0

不會解析所有的空格,這使得每次都比分配一個新的字符串更慢嗎? – svick 2012-04-15 12:28:22

+0

@弗拉德,是的,你可以做到這一點。只是不要傳遞該字符串,並保持私密。這樣你就不會違反其他代碼所做的假設。 StringBuilder在內部使用這種技術。當你使用StringBuilder時,它只是把你的內部緩衝區傳給你。 StringBuilder.ToString通常是O(1)。 – usr 2012-04-15 12:37:49

2

,我會用一個狀態機

這可能看起來像:

enum State 
{ 
    Separator, Sign, Mantisse etc. 
} 
State CurrentState = State.Separator; 
int Prefix, Exponent, Mantisse; 
foreach(var ch in InputString) 
{ 
    switch(CurrentState) 
    { // set new currentstate in dependence of ch and CurrentState 
     case Separator: 
      GotNewDouble(Prefix, Exponent, Mantisse); 


    } 

} 
+0

你的意思是手動解析,而不使用TryParse? – Vlad 2012-04-15 13:16:22

+0

是的,如果你正在使用TryParse,你需要每次都有一個新的字符串實例。那麼你有相同的行爲,如var values = string.Split('').Select(s => double.Parse(s))。ToArray(); – user287107 2012-04-15 13:22:51

+0

那麼,手動解析通常是緩慢的,越野車,我想盡可能避免重新發明車輪。 – Vlad 2012-04-15 17:06:48