2015-04-01 106 views
0

根據Regex文檔,使用RegexOptions.ExplicitCapture使得正則表達式只匹配命名組,如(?<groupName>...);但在行動上它做了一些有點不同的事情。如何使正則表達式只捕獲命名組

考慮的幾行代碼:

static void Main(string[] args) { 
    Regex r = new Regex(
     @"(?<code>^(?<l1>[\d]{2})/(?<l2>[\d]{3})/(?<l3>[\d]{2})$|^(?<l1>[\d]{2})/(?<l2>[\d]{3})$|(?<l1>^[\d]{2}$))" 
     , RegexOptions.ExplicitCapture 
    ); 
    var x = r.Match("32/123/03"); 
    r.GetGroupNames().ToList().ForEach(gn => { 
     Console.WriteLine("GroupName:{0,5} --> Value: {1}", gn, x.Groups[gn].Success ? x.Groups[gn].Value : ""); 
    }); 
} 

當你運行這段代碼,你會看到的結果中包含一個名爲組,而我沒有在我的正則表達式命名0組!

GroupName: 0 --> Value: 32/123/03 
GroupName: code --> Value: 32/123/03 
GroupName: l1 --> Value: 32 
GroupName: l2 --> Value: 123 
GroupName: l3 --> Value: 03 
Press any key to continue . . . 

請問有人請向我解釋這種行爲?

+2

的*零組*匹配整個正則表達式 – 2015-04-01 18:56:43

+0

@AlexK。你的意思是我不得不忽視第一組? – Achilles 2015-04-01 19:07:38

回答

1

總是有組0:這是整場比賽。基於定義組的開括號的序數位置,編號組相對於1。正則表達式(格式爲清楚起見):

(?<code> 
^
    (?<l1> [\d]{2}) 
/
    (?<l2> [\d]{3}) 
/
    (?<l3> [\d]{2}) 
    $ 
| 
^
    (?<l1>[\d]{2}) 
/
    (?<l2>[\d]{3}) 
    $ 
| 
    (?<l1> ^[\d]{2} $) 
) 

你的表達會原路返回,所以你可能會考慮簡化您的正則表達式。這可能是更清晰,更高效:

static Regex rxCode = new Regex(@" 
^     # match start-of-line, followed by 
    (?<code>    # a mandatory group ('code'), consisting of 
    (?<g1> \d\d)  # - 2 decimal digits ('g1'), followed by 
    (     # - an optional group, consisting of 
    /    # - a literal '/', followed by 
     (?<g2> \d\d\d) # - 3 decimal digits ('g2'), followed by 
     (    # - an optional group, consisting of 
     /   #  - a literal '/', followed by 
     (?<g3> \d\d) #  - 2 decimal digits ('g3') 
    )?    #  - END: optional group 
    )?     # - END: optional group 
)     # - END: named group ('code'), followed by 
    $     # - end-of-line 
" , RegexOptions.IgnorePatternWhitespace|RegexOptions.ExplicitCapture); 

一旦你的,這樣的事情:

string[] texts = { "12" , "12/345" , "12/345/67" , } ; 

foreach (string text in texts) 
{ 
    Match m = rxCode.Match(text) ; 
    Console.WriteLine("{0}: match was {1}" , text , m.Success ? "successful" : "NOT successful") ; 
    if (m.Success) 
    { 
    Console.WriteLine(" code: {0}" , m.Groups["code"].Value) ; 
    Console.WriteLine(" g1: {0}" , m.Groups["g1"].Value) ; 
    Console.WriteLine(" g2: {0}" , m.Groups["g2"].Value) ; 
    Console.WriteLine(" g3: {0}" , m.Groups["g3"].Value) ; 
    } 
} 

產生預期

12: match was successful 
    code: 12 
    g1: 12 
    g2: 
    g3: 
12/345: match was successful 
    code: 12/345 
    g1: 12 
    g2: 345 
    g3: 
12/345/67: match was successful 
    code: 12/345/67 
    g1: 12 
    g2: 345 
    g3: 67 
+0

+1,並感謝我的正則表達式的更清潔版本。我知道它可以用更清晰的方式表達出來,但是因爲它起作用,而且我很懶,所以我就這麼保持它!我會很好的使用你的regex版本,我會忽略** 0 **組。 – Achilles 2015-04-01 19:26:47

0

命名

^(?<l1>[\d]{2})/(?<l2>[\d]{3})/(?<l3>[\d]{2})$|^(?<l1>[\d]{2})/(?<l2>[\d]{3})$|(?<l1>^[\d]{2}$) 

enter image description here

試試這個(我從你的正則表達式中刪除第一組) - see demo

+0

它仍然是一樣的。 ** 0 **組在那裏;並在一個側面說明,我需要'code'組被捕獲。 GroupName:0 - > Value:32/123/03 GroupName:l1 - > Value:32 GroupName:l2 - > Value:123 GroupName:l3 - > Value:03 按任意鍵繼續。 。 。 – Achilles 2015-04-01 19:00:59

+0

用於文本「123」的模式「\ d +」 - 具有1組= 123的返回數組。 用於文本「123」的模式「(\ d +)」 - 具有2組= 123和123的返回數組。 模式「 「 \ d +)」爲文本「123」 - 返回數組與2組123也是123. 我認爲這是應該的。 – GRUNGER 2015-04-01 19:08:56

+0

'\ d +'未被命名。 '(? \ d +)'將被命名並且這相同。我認爲'GetGroupNames()'方法和'RegexOptions.ExplicitCapture'的解釋有問題。 – Achilles 2015-04-01 19:12:58