我要處理數千個字符串(平均大小約爲150kB)。他們每個人都包含以下形式的零個或多個字符串:在C中提取子字符串的最快方法
<a href="/link/i/want">Fixed_String</a>
我想提取所有這樣的鏈接,並把它們放入一個列表。
此外,還有另一個固定的字符串後,我所尋找的字符串將不會出現。
獲取字符串的最快方法是什麼?
我要處理數千個字符串(平均大小約爲150kB)。他們每個人都包含以下形式的零個或多個字符串:在C中提取子字符串的最快方法
<a href="/link/i/want">Fixed_String</a>
我想提取所有這樣的鏈接,並把它們放入一個列表。
此外,還有另一個固定的字符串後,我所尋找的字符串將不會出現。
獲取字符串的最快方法是什麼?
子串()選項
正如泰奧曼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);
}
導致含有鏈接的集合:
假設字符串格式正確的HTML格式,您可以輕鬆地用XmlReader類進行解析,該類非緩存且只轉發(這使得它非常快速)。您只需尋找適當的節點來檢索其'href'屬性的值。
您也可以使用像.SubString()
這樣的普通字符串操作,但是您必須編寫許多子例程來處理異常情況。這裏的要點是避免RegEx,因爲它是最慢的。
你確定嗎?我還沒有測試過,但對我而言似乎並不那麼明顯,一系列正則表達式匹配比XmlReader慢得多......沒時間現在測試,但稍後可能會用到它:) – Tao 2011-06-02 12:47:05
這不是我在這裏發言,這是經驗:) RegEx引擎總是比只轉發和非緩存解析器(大約是我的經驗的10倍)慢。嘗試使用RegEx和'XmlReader.Create(..)'從大文檔中提取單個元素的屬性,然後您會看到... – 2011-06-02 13:24:24
我覺得在這種情況下有字符串這是足夠大的,平均和其中包含零個或多個子最好的辦法,是用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
}
}
手工解析的位可能是解決這個問題的最快方法。正則表達式也是可能的,因爲它實際上只是解析鏈接而不是整個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可能是你最好的選擇,或者如果它不能被幫助,可能是一個正確的正則表達式。我發佈了這個手冊解析,所以你有另一個可以做性能測試的選擇。
一般正則表達式是小文件的速度。如果文件大小變大(按我的經驗大於〜60Kb),則Regex變慢(即使是靜態,編譯等)。在很好的英語描述找到確切的情況:
Stripping Out Empty XmlElements in a Performant Way and the Bus Factor
玩得開心發現什麼是「高巴士因子」。它給我帶來了一天的好心情。
「Fixed_String」部分總是完全一樣嗎? – LukeH 2011-06-02 12:20:34
@LukeH:是的,這是一個固定的字符串。 – Hui 2011-06-02 12:22:31