php正则表达式邮编匹配问题?

Bohr
  • 6.4k
美国的邮政编码的规则是 5 个数字或者 5 个数字连上 4 个数字,如 12345 或者 54321-1234 ,如果要匹配所有的邮编,则正确的正则表达式为:
\d{5}-\d{4}|\d{5}
//错误写法
\d{5}|\d{5}-\d{4}
下面的错误写法,只能匹配到 5 位数字及 9 位数字的前 5 位数字的情况,而不能匹配 9 位数字的邮编。

为什么下面那种写法就是错的,如果是9位数的邮编,和上面那个写法有什么不同吗?

回复
阅读 2.7k
5 个回答

我试了一下

12345-6789
12345-6789

这个文本 
你(\d{5})|(\d{5}-\d{4})和(\d{5}-\d{4})|(\d{5})的结果不一样 
(\d{5})|(\d{5}-\d{4})只能匹配到12345
(\d{5}-\d{4})|(\d{5})只能匹配到12345-6789

这说明这个或运算的时候 从左往右计算 计算得到匹配结果就完事了 不会去试另一个了

但是如果用下面这个文本

12345-6789
12345
你就会发现(\d{5}-\d{4})|(\d{5})都能匹配到 但是(\d{5})|(\d{5}-\d{4})只能匹配到12345
道理和上面的一样 从左到有 匹配完就结束 不会继续试后面的了


因为后四位是可选的,推荐另外一种写法:

\d{5}(-\d{4})?

\d{5} : 匹配5位的连续数字;
(-\d{4}) : 这是一个子表达式,匹配-和四位连续数字;
? : 问号表示前面的子表达式最多只允许出现一次。

看了下楼主的问题,主要原因是对或“|”的不理解。另外对如何写正则表达式可能不太理解。

首先,我们看下|为什么不能匹配?

正则表达式: d{5}|d{5}-d{4}
当你使用preg_match来匹配的时候,它获取到第一个匹配成功的时候,就不会继续往下进行,因此你只能得到5位数。

当你使用preg_match_all它会匹配“或”两侧的规则,当给一个字符串“54321-1234”,会先所有的5位数会先被匹配出来,第一个规则后剩下的结果是-1234此时再去匹配右侧的规则显然不符合d{5}-d{4},也就不会成功。

另外看下如何写正则表达式?

假如要匹配一个东西,首先要分析哪些是必须项,哪些是可选项。然后就是丢掉必须项,先考虑可选项该如何写。最后再加上必须项。

比如你的需求,5位数是必然出现的,-1234 这种是可能出现的,所以先写 (-d{4})? 再来加上必须项:

\d{5}(-\d{4})?

ok,你都不需要用或 “|” 。

因为JavaScript正则表达式的分支符号|是顺序执行的,不是优先匹配原则。

顺序执行的意思就是只要前面的一种选择匹配成功了,分支后面的情况就不再继续匹配。

优先匹配的意思就是,即使前面的一种可能性匹配成功了,引擎还要对后面的可能性进行匹配,最后匹配成功的长度最长的那个分支,作为匹配结果。

由于JavaScript正则引擎对分支|采取的顺序执行,所以通用的解决方法就是:长度最短的一种可能的分支,放在最后。对于邮编这个案例,要把长度最短的5位邮编的可能性放在最后面。

| 是或的关系·如果前面一个匹配到了,后面就不会匹配了

你知道吗?

宣传栏