是否有更优雅的regex解决方案可用于在短字符串中匹配多个模式



在过去的两个小时里,我一直在为此而流泪,忍不住觉得有一个简单的解决方案我看不到。我正在尝试处理一个字符串——一个门牌号码(你可以在街道地址中找到),并将其分解为四个组成部分。

字符串可以有四种基本的不同模式

A. a numeric value consisting of one or more digits e.g. 5
B. one or more digits followed by a single alphabetic character e.g. 5A
C. two numeric values consisting of one or more digits and joined by a
   hyphen e.g. 5-6
D. two alphanumeric values (with each consisting of one or more digits 
   followed by a single alphabetic character) split by a hyphen e.g. 5A-6B

字符串应该总是以数字字符(1-9)开头,但其他所有内容都是可选的

我需要得到四个值,如下

startnumber - it would be 5 in the example above
startsuffix - it would be A in the example above
endnumber - it would be 6 in the example above
endsuffix - it would be B in the example above

startnumber和endnumber可以是一个或多个数字。startsuffix和endsuffix必须是单个字母字符

我的表单上有一些基本的验证,只允许输入0-9、A-Z和"-"字符

我一直在使用很多if语句、is_numerics、strpos等,但我忍不住觉得有一个更明显的答案——也许使用正则表达式,但我真的很挣扎。如有任何帮助,我们将不胜感激。

我认为这个regexp应该做到这一点:

(d+)([A-Z]?)(?:-(d+)([A-Z]?))?

捕获组1到4对应于您列出的四个值。

这也将匹配类似5-6B的地址。正则表达式没有内存,因此要求在第二部分中有一个字母当且仅当第一部分中有字母时是不可行的,除非你使用4个不同正则表达式的联合来处理每种情况。

使用这个正则表达式,调用代码可以简单地检查捕获组2和4是否都为空或都不为空。

您可以尝试以下操作(这是在原始PCRE中):

([0-9]+)([A-Z])?|([0-9]+)-([0-9]+)|([0-9]+)([A-Z])-([0-9]+)([A-Z])

问题是捕获组会因运行而异。如果你不关心验证特定的格式,那么你可以试试这个:

([0-9]+)([A-Z])?(?:-([0-9]+)([A-Z])?)?

在这种情况下,第一个捕获组将保存startnumber、第二个startsuffix、第三个endnumber和第四个endsuffix。与我的第一个例子不同,它不会确认输入是否与您指定的格式之一匹配(即,它将接受2D-4或2-4D),但如果这不是问题,那么它可能更容易使用。

这是一个破解,但它应该可以工作:

(?<startnumber>d+(?:(?<startsuffix>[A-Z]))?)(?:-(?<endnumber>d+(?:(?<endsuffix>[A-Z]))?))?

试试这个:

(d+(?:[A-Z])?(?:-d+(?(2)[A-Z])?)?)

最新更新