我遇到了解析自定义电话号码的正则表达式问题:
代码示例如下。
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
答案 0 :(得分: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);
正如您所看到的,我对您的代码进行了一些其他更改,最重要的是从([-|/|#| |]|)
切换到[-/# ]
。括号内的管道只匹配文字|
,我很确定你不想要它。最后一根管道使隔板成为可选;我希望他们不真的必须是可选的,因为这会使这项工作变得更加困难。
答案 1 :(得分:1)
自己和其他响应者忽略了两件事。
首先,反向工作更有意义,换句话说从右到左,因为文本末尾比起初更多需要字段。通过消除对WTV和国家代码的怀疑,正则表达式解析器变得更容易工作(虽然在写作模式的人的知识上更难)。
第二个是在regex(?()|())中使用if条件。这允许我们测试场景并实现一种匹配模式而不是另一种。我在我的博客上描述了if条件Regular Expressions and the If Conditional。下面的模式测试是否有WTV&amp;国家/地区,如果匹配,如果不匹配则检查可选国家/地区。
而不是连接模式,为什么不使用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
注意: