2012-03-30 61 views
0

我遇到與解析自定義的電話號碼正則表達式的問題:重疊的規則與命名組

  1. 值匹配「wtvCode」組是可選的;
  2. 匹配「countryCode」組的值是可選的;
  3. 對於某些值,countryCode規則與areaCityCode規則重疊。在這種情況下,當countryCode缺失時,其表達式會捕獲areaCityCode值。

代碼示例如下。

Regex regex = new Regex(string.Concat(
    "^(", 
    "(?<wtvCode>[A-Z]{3}|)", 
    "([-|/|#| |]|)", 
    "(?<countryCode>[2-9+]{2,5}|)", 
    "([-|/|#| |]|)", 
    "(?<areaCityCode>[0-9]{2,3}|)", 
    "([-|/|#| |]|))", 
    "(?<phoneNumber>(([0-9]{8,18})|([0-9]{3,4}([-|/|#| |]|)[0-9]{4})|([0-9]{4}([-|/|#| |]|)[0-9]{4})|([0-9]{4}([-|/|#| |]|)[0-9]{4}([-|/|#| |]|)[0-9]{1,5})))", 
    "([-|/|#| |]|)", 
    "(?<foo>((A)|(B)))", 
    "([-|/|#| |]|)", 
    "(?<bar>(([1-9]{1,2})|)", 
    ")$" 
)); 

string[] validNumbers = new[] { 
    "11-1234-5678-27-A-2", // missing wtvCode and countryCode 
    "48-1234-5678-27-A-2", // missing wtvCode and countryCode 
    "55-48-1234-5678-27-A-2" // missing wtvCode 
}; 

foreach (string number in validNumbers) { 
    Console.WriteLine("countryCode: {0}", regex.Match(number).Groups["countryCode"].Value); 
    Console.WriteLine("areaCityCode: {0}", regex.Match(number).Groups["areaCityCode"].Value); 
    Console.WriteLine("phoneNumber: {0}", regex.Match(number).Groups["phoneNumber"].Value); 
} 

的輸出是:

// First number 
// countryCode:    <- correct 
// areaCityCode: 11   <- correct, but that's because "11" is never a countryCode 
// phoneNumber: 1234-5678-27 <- correct 

// Second number 
// countryCode: 48   <- wrong, should be "" 
// areaCityCode:    <- wrong, should be "48" 
// phoneNumber: 1234-5678-27 <- correct 

// Third number 
// countryCode: 55   <- correct 
// areaCityCode: 48   <- correct 
// phoneNumber: 1234-5678-27 <- correct 

我至今未能在一個固定的方式正則表達式,它涵蓋了我所有的約束和不亂用COUNTRYCODE和areaCityCode時一個值符合兩個規則。有任何想法嗎?

在此先感謝。


更新

的電話國家代碼正確的正則表達式可以在這裏找到:https://stackoverflow.com/a/6967885/136381

+1

「55-48-1234-5678-27-A-2」// missing countryCode - > missing wtvCode code? – zishe 2012-03-30 04:14:32

回答

2

首先,我建議使用?量詞把事情可選,而不是空的替代你」現在重新使用。在國家代碼的情況下,添加另一個?以使其非貪婪。這樣它會嘗試最初捕獲areaCityCode組中的第一批數字。只有在總體匹配失敗的情況下,它纔會返回並使用countryCode組。

Regex regex = new Regex(
    @"^ 
    ((?<wtvCode>[A-Z]{3}) [-/# ])? 
    ((?<countryCode>[2-9+]{2,5}) [-/# ])?? 
    ((?<areaCityCode>[0-9]{2,3}) [-/# ])? 
    (?<phoneNumber> [0-9]{8,18} | [0-9]{3,4}[-/# ][0-9]{4}([-/# ][0-9]{1,5})?) 
    ([-/# ] (?<foo>A|B)) 
    ([-/# ] (?<bar>[1-9]{1,2}))? 
    $", 
    RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); 

正如你所看到的,我做了一些其他修改了代碼,最重要的是從([-|/|#| |]|)[-/# ]開關。括號內的管道只與|相符,我敢肯定你不想要。最後一個管道使分隔符可選;我希望他們不要真的必須是可選的,因爲這會使這項工作更加困難。

+0

你的表情看起來不錯,以及你的建議。我正在測試它。 – 2012-03-30 13:39:53

+0

你對「([ - |/|#| | | | |)」)是正確的。我正在使用您的分隔符模式。 – 2012-03-30 15:16:33

1

自己和其他響應者忽略了兩件事。

首先是反向工作更有意義,換句話說,從右到左,因爲文本末尾有比開始時更多的必填字段。通過消除WTV和國家代碼的疑問,正則表達式解析器的工作變得更加容易(,儘管在編寫模式的人的智力上更難)。

第二個是在正則表達式(?()|())中使用if條件。這使我們能夠測試一個場景並實現一個匹配模式。我在我的博客上描述如果條件爲Regular Expressions and the If Conditional。下面的模式測試了WTV是否有WTV &國家,如果是的話它是否與之匹配,如果不是則檢查可選國家。

此外而不將爲什麼不使用IgnorePatternWhitespace的一種花紋的評論,因爲我出現如下格局:

string pattern = @" 
^ 
(?([A-Z][^\d]?\d{2,5}(?:[^\d])) # If WTV & Country Code (CC) 
    (?<wtvCode>[A-Z]{3})   # Get WTV & CC 
    (?:[^\d]?) 
    (?<countryCode>\d{2,5}) 
    (?:[^\d])     # Required Break 
    |       # else maybe a CC 
    (?<countryCode>\d{2,5})?  # Optional CC 
    (?:[^\d]?)     # Optional Break 
) 
(?<areaCityCode>\d\d\d?)  # Required area city 
(?:[^\d]?)      # Optional break (OB) 
(?<PhoneStart>\d{4})   # Default Phone # begins 
(?:[^\d]?)      # OB 
(?<PhoneMiddle>\d{4})   # Middle 
(?:[^\d]?)      # OB 
(?<PhoneEnd>\d\d)    # End 
(?:[^\d]?)      # OB 
(?<foo>[AB])     # Foo? 
(?:[^AB]+) 
(?<bar>\d) 
$ 
"; 

    var validNumbers = new List<string>() { 
    "11-1234-5678-27-A-2", // missing wtvCode and countryCode 
    "48-1234-5678-27-A-2", // missing wtvCode and countryCode 
    "55-48-1234-5678-27-A-2", // missing wtvCode 
    "ABC-501-48-1234-5678-27-A-2" // Calling Belize (501) 
}; 

    validNumbers.ForEach(nm => 
       { 
        // IgnorePatternWhitespace only allows us to comment the pattern; does not affect processing 
        var result = Regex.Match(nm, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.RightToLeft).Groups; 

        Console.WriteLine (Environment.NewLine + nm); 
        Console.WriteLine("\tWTV code : {0}", result["wtvCode"].Value); 
        Console.WriteLine("\tcountryCode : {0}", result["countryCode"].Value); 
        Console.WriteLine("\tareaCityCode: {0}", result["areaCityCode"].Value); 
        Console.WriteLine("\tphoneNumber : {0}{1}{2}", result["PhoneStart"].Value, result["PhoneMiddle"].Value, result["PhoneEnd"].Value); 

       } 
    ); 

結果:

11-1234-5678-27-A-2 
    WTV code : 
    countryCode : 
    areaCityCode: 11 
    phoneNumber : 1234567827 

48-1234-5678-27-A-2 
    WTV code : 
    countryCode : 
    areaCityCode: 48 
    phoneNumber : 1234567827 

55-48-1234-5678-27-A-2 
    WTV code : 
    countryCode : 55 
    areaCityCode: 48 
    phoneNumber : 1234567827 

ABC-501-48-1234-5678-27-A-2 
    WTV code : ABC 
    countryCode : 501 
    areaCityCode: 48 
    phoneNumber : 1234567827 

注:

  • 如果國家代碼和城市代碼之間沒有分隔符, 有沒有辦法ap arser可以確定什麼是城市,什麼是 國家。
  • 您原來的國家/地區代碼模式失敗[2-9],其中有0的國家/地區的任何 國家/地區失敗。因此我將它改爲[2-90]。
+0

非常明確,謝謝。而且,[2-90]也不適用於電話國家/地區代碼。我結束了使用這裏描述的模式:http://stackoverflow.com/a/6967885/136381 – 2012-03-30 18:17:44