2011-08-28 22 views
1

我需要使用.NET正則表達式來取消標記文件的<value>標籤之間的一些值,比如這個(複製\粘貼節選):.NET正則表達式解析標記在某些部分重複的值而不是其他

<Title>Section1</Title> 

<attributeArray><name>Name1</name><value>Value1</value></attributeArray> 

<attributeArray><name>Name2</name><value>Value2</value></attributeArray> 

<attributeArray><name>Name3</name><value>Value3</value></attributeArray> 

<attributeArray><name>Name4</name><value>Value4</value></attributeArray> 

<Title>Section2</Title> 

<attributeArray><name>Name1</name><value>Value1</value></attributeArray> 

<attributeArray><name>Name2</name><value>Value2</value></attributeArray> 

<attributeArray><name>Name3</name><value>Value3</value></attributeArray> 

<attributeArray><name>Name4</name><value>Value4</value></attributeArray> 

</node> 

實際內容包括6個部分。我遇到的問題是每個部分的所有標籤名稱都是相同的,我只需要從部分2中提取值(因此不包括1,3,4,5,6)。

我有這個掙扎了幾天,並嘗試了各種條件表達式這是新的我是這樣的:

(?(<node>Section2)(.*?<value>(?<Value>.*?)<\/value>.*?)) 

如果第2節,然後解析值鍵,但只提取第一個值 - 它不會遍歷標記的每個<value>。而標記通常有大約10個我需要提取的值(在上面的示例中縮寫)。

這不是在代碼中完成的,所以我沒有使用XML解析器的自由。

任何建議將不勝感激 - 或者如果我可以進一步澄清讓我知道。

事後考慮 - 如果有一種方法可以將標題的文本與每個值匹配,那麼我可以解析所有6個部分,但後來我可以根據後面的部分篩選結果也可以工作。

例如:

match1 
group1 = Section2 
group2 = Value1 

match2 
group1 = Section2 
group2 = Value2 

match3 
group1 = Section2 
group2 = Value3 

match4 
group1 = Section2 
group2 = Value4 

謝謝!

+0

什麼是最後的''和模式中的''元素?另外,你是否可以在解析數據時自由運行任何代碼? (如果是這樣,爲什麼不是XML解析器?我問,因爲你說你可以*過濾結果,但不能做其他事情) – Kobi

+0

@Kobi OP說XML解析器不是一個選項。 – NullUserException

+0

@Null - 我知道,但OP也說「但我可以稍後根據我之後的部分篩選結果」。我感到好奇的是,OP可以運行* some *代碼,我對它的侷限性感興趣。通常,當你需要嚴格的正則表達式時,你沒有這個選項。 – Kobi

回答

2

這裏有一個選項:

(?: 
    <Title>Section2</Title> # Match the header 
    |       # or 
    \G(?!\A)     # Match where the previous match ended 
)\s* 
<attributeArray> 
    <name>(?<name>[^<]*)</name> 
    <value>(?<value>[^<]*)</value> 
</attributeArray> 

的第一場比賽包括頭,和下面的比賽必須開始,其中前一個結束。
工作例如:http://regexhero.net/tester/?id=321ce843-923d-4556-9b99-dbb72175929a


請注意,如果您有沒有價值或標題之間提其他元素上面會失敗。你可以避開這一有可能是低效率的模式,用事實淨正則表達式可以有可變長度lookbehinds:

(?<=       # lookbehind - check that before the current position 
    <Title>Section2</Title> # we can see the wanted title, 
    (?:(?!<Title>).)*   # followed by no more title between it and here. 
) 
<attributeArray> 
    <name>(?<name>[^<]*)</name> 
    <value>(?<value>[^<]*)</value> 
</attributeArray> 

例子:http://regexhero.net/tester/?id=743c4de6-1b8a-48a4-a69b-63f3624de594

如果你願意,你可以將標題更改爲<Title>(?<title>[^<]*)</Title> ,捕獲文件中的所有值,並按照想要的標題過濾 - 它將被添加到每個匹配中。


最後,這裏有一個類似的做法,將在其他口味的工作:它捕獲鍵/值對標題Section3之前,假設它是良好有序:

<attributeArray> 
    <name>(?<name>[^<]*)</name> 
    <value>(?<value>[^<]*)</value> 
</attributeArray> 
(?= 
    (?:(?!<Title>).)* 
    <Title>Section3</Title> 
) 

例子:http://regexhero.net/tester/?id=8d8ae0e8-5f10-439f-a5a5-50d0b4e73bd2

+0

非常好!我回到了這裏,認爲我應該添加一個基於非Captures的解決方案,以顯示這可以在.NET以外的其他版本中完成,只是發現它已經被處理。 :d –

1

我建議使用CaptureCollection:

string s = @"<Title>Section1</Title> 
<attributeArray><name>Name1</name><value>Value1-1</value></attributeArray> 
<attributeArray><name>Name2</name><value>Value1-2</value></attributeArray> 
<attributeArray><name>Name3</name><value>Value1-3</value></attributeArray> 
<attributeArray><name>Name4</name><value>Value1-4</value></attributeArray> 

<Title>Section2</Title> 
<attributeArray><name>Name1</name><value>Value2-1</value></attributeArray> 
<attributeArray><name>Name2</name><value>Value2-2</value></attributeArray> 
<attributeArray><name>Name3</name><value>Value2-3</value></attributeArray> 
<attributeArray><name>Name4</name><value>Value2-4</value></attributeArray> 

<Title>Section3</Title> 
<attributeArray><name>Name1</name><value>Value3-1</value></attributeArray> 
<attributeArray><name>Name2</name><value>Value3-2</value></attributeArray> 
<attributeArray><name>Name3</name><value>Value3-3</value></attributeArray> 
<attributeArray><name>Name4</name><value>Value3-4</value></attributeArray>"; 

Regex r = new Regex(
    @"<Title>(Section2)</Title>(?:\s*<attributeArray>.*?<value>(.*?)</value></attributeArray>)+"); 
Match m = r.Match(s); 
if (m.Success) 
{ 
    string section = m.Groups[1].Value; 
    int i = 0; 
    foreach (Capture c in m.Groups[2].Captures) 
    { 
    Console.WriteLine("match{0}\ngroup1 = {1}\ngroup2 = {2}\n", 
         ++i, section, c.Value); 
    } 
} 

m.Groups[2].Value將返回Value2-4,在最後件事組#2被捕獲。但所有中間捕獲都保留,可通過Captures property訪問。

相關問題