2011-06-02 26 views
1

我要處理數千個字符串(平均大小約爲150kB)。他們每個人都包含以下形式的零個或多個字符串:在C中提取子字符串的最快方法

<a href="/link/i/want">Fixed_String</a> 

我想提取所有這樣的鏈接,並把它們放入一個列表。

此外,還有另一個固定的字符串後,我所尋找的字符串將不會出現。

獲取字符串的最快方法是什麼?

+0

「Fixed_String」部分總是完全一樣嗎? – LukeH 2011-06-02 12:20:34

+0

@LukeH:是的,這是一個固定的字符串。 – Hui 2011-06-02 12:22:31

回答

3

子串()選項

正如泰奧曼Soygul指出,有一個子()選項,我不知道這是否是或快或慢,因爲我沒有測試他們並排。

現在,這沒有適當地分成子方法,但應該給你的一般想法。
我只是使用一個ReadOnlyCollection因爲這是我習慣於當不需要進一步操縱列表。將其更改爲您喜歡的任何輸出列表類型。

someText變量最有可能最終會偏離GetLinks的參數。

public ReadOnlyCollection<string> GetLinks() 
{ 
    string startingText = "href=''"; 
    string endText = "''>"; 
    string stopText = "Fixed_String"; 
    string someText = @"what is this text <a href=''/link/i/want''>somenormallink</a> some random text <a href=''/another link/i/want''>Fixed_String</a> some more radnom txt "; 

    List<string> myLinks = new List<string>(); 

    string[] rawLinks = someText.Split(new string[] { "<a " }, StringSplitOptions.None); 

    foreach (string rawLink in rawLinks) 
    { 
     if (!rawLink.StartsWith(startingText)) 
     { 
      continue; 
     } 

     myLinks.Add(rawLink.Substring(startingText.Length, rawLink.IndexOf(endText, 1) - startingText.Length)); 


     if (rawLink.Contains(stopText)) 
     { 
      break; 
     } 
    } 


    return new ReadOnlyCollection<string>(myLinks); 
} 

導致含有鏈接的集合:
enter image description here

3

假設字符串格式正確的HTML格式,您可以輕鬆地用XmlReader類進行解析,該類非緩存且只轉發(這使得它非常快速)。您只需尋找適當的節點來檢索其'href'屬性的值。

您也可以使用像.SubString()這樣的普通字符串操作,但是您必須編寫許多子例程來處理異常情況。這裏的要點是避免RegEx,因爲它是最慢的。

+1

你確定嗎?我還沒有測試過,但對我而言似乎並不那麼明顯,一系列正則表達式匹配比XmlReader慢得多......沒時間現在測試,但稍後可能會用到它:) – Tao 2011-06-02 12:47:05

+0

這不是我在這裏發言,這是經驗:) RegEx引擎總是比只轉發和非緩存解析器(大約是我的經驗的10倍)慢。嘗試使用RegEx和'XmlReader.Create(..)'從大文檔中提取單個元素的屬性,然後您會看到... – 2011-06-02 13:24:24

0

我覺得在這種情況下有字符串這是足夠大的,平均和其中包含零個或多個子最好的辦法,是用Regex class這樣的:

string anchorPattern = @"<(.|/)a(.|\n)+?>"; 

foreach (string str in strings) 
{ 
    Regex regex = new Regex(anchorPattern); 

    foreach (Match match in regex.Matches(str)) 
    { 
     // do here what you want with substring in match.Value 
    } 

} 
2

手工解析的位可能是解決這個問題的最快方法。正則表達式也是可能的,因爲它實際上只是解析鏈接而不是整個HTML文檔的一個非常簡單的例子,但是它很容易扼殺這些大文件,性能明智。

現在,讓我說這個,我沒有測試過這個,我覺得有點骯髒張貼它(我相信它需要更多的邊緣情況下檢查,以避免錯誤),但在這裏你去:

const char[] quotes = new char[] { '"', '\'' }; 

    private List<string> ExtractLinks(string html) 
    { 
     var links = new List<string>(); 
     string searchFor = ">Fixed_String</a>"; 

     for (int i = html.IndexOf(searchFor); i >= 0; i = html.IndexOf(searchFor, i + searchFor.Length)) 
     { 
      string href = ExtractHref(html, i); 
      if (!String.IsNullOrEmpty(href)) 
       links.Add(href); 
     } 

     return links; 
    } 

    private string ExtractHref(string html, int backtrackFrom) 
    { 
     int hrefStart = -1; 

     // Find "<a", but limit search so we don't backtrack forever 
     for (int i = backtrackFrom; i > backtrackFrom - 255; i--) 
     { 
      if (i < 0) 
       return null; 

      if (html[i] == '<' && html[i + 1] == 'a') 
      { 
       hrefStart = html.IndexOf("href=", i); 
       break; 
      } 
     } 

     if (hrefStart < 0) 
      return null; 

     int start = html.IndexOfAny(quotes, hrefStart); 
     if (start < 0) 
      return null; 

     int end = html.IndexOfAny(quotes, start + 1); 
     if (end < 0) 
      return null; 

     return html.Substring(start + 1, end - start - 1); 
    } 

XmlReader可能是一個不行,因爲你很可能不能保證這些文件是XHTML格式。如果你想做適當的解析,HTML Agility Pack可能是你最好的選擇,或者如果它不能被幫助,可能是一個正確的正則表達式。我發佈了這個手冊解析,所以你有另一個可以做性能測試的選擇。

相關問題