我想提出一种解决像这样的问题的方法。主要的任务是可以用与其他Ruby代码相同的方式构造复杂的正则表达式:创建可轻松测试的小代码模块,然后组合这些模块。
考虑必须匹配正则表达式的第一个字符串。
s = "201-Grandview-Dr_Early_TX_76802"
与此字符串不包含字符需要进行转义,我们可以创建一个正则表达式,将正好由仅仅用斜杠替换双引号并添加启动的字符串此字符串匹配(\A
)和结束串(\z
)主播:
r = /\A201-Grandview-Dr_Early_TX_76802\z/
#=> /\A201-Grandview-Dr_Early_TX_76802\z/
s =~ r
#=> 0
这是我们所拥有的:
/\A201-Grandview\-Dr_Early_TX_76802\z/
⬆︎street number
⬆︎street name
⬆︎street name suffix
⬆︎city
⬆︎state
⬆︎zip
想必正则表达式应该垫查找字符串当且仅当字符串包含这六个字段中的每一个的允许值并在相邻字段之间显示格式。
让我们先为六个字段中的每一个规定一个单独的正则表达式。自然,所有这些正则表达式可能都需要进行修改以适应需求。
门牌号码
典型街道数字可能是 “221”, “221B”, “221B”。假设我们也可能有“A19”或“221BZ”而不是“221-B”。然后,我们可能会这样写:
number = /[[:alnum:]]+/
(在Regexp搜索“POSIX”)
街道名称
我假设的街道名称由一个分隔的单个词或多个单词的单个空格,其中每个单词都是小写,除了首字母大写。
street = /[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*/
/[[:upper:]][[:lower:]]+
的第一个字相匹配,(?:\s[[:upper:]][[:lower:]])*
的空间,随后通过一个大写字相匹配时,重复零次或更多次((?:...)
是非捕获基团。尾随*
装置重复零次或多次。)
街道名称后缀
我承担的街道名称后缀(如,“街”,“圣“)是一个字,除了第一个字符,这是大写,任选一个周期结束全部小写:
suffix = /[[:upper:]][[:lower:]]+\.?/
市
我假定城市的名字有相同的要求做的街道名称:
city = street
#=> /[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*/
国家
个国家由两个大写字母给出:
state = /[[:upper:]]{2}/
我们可以通过书面形式更精确:
state = Regexp.union %w| AL AK AZ ... |
但后来我们不得不每一个领土成为一个新的状态或时间进行更新(可能是由于最近的事件)一个国家从工会中脱身。
邮编
邮政编码是五位数字或九个数字与第一四位数字之后的破折号或连字符。
zip = /\d{5}(?:-\d{4})?/
使用
/\A201-Grandview-Dr_Early_TX_76802\z/
为我们的模式,我们的整体正则表达式因此如下:
r1 =/
\A # match start of string
#{number}
-
#{street}
-
#{suffix}
_
#{city}
_
#{state}
_
#{zip}
\z # match end of string
/x # free-spacing regex definition mode
#=>/
# \A # match start of string
# /(?-mix:[[:alnum:]]+)
# -
# (?-mix:[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*)
# -
# (?-mix:[[:upper:]][[:lower:]]+\.?)
# _
# (?-mix:[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*)
# _
# (?-mix:[[:upper:]]{2})
# _
# (?-mix:\d{5}(?:-\d{4})?)
# \z # match start of string
/x
让我们试试它的第一个字符串和变体:
"201-Grandview-Dr_Early_TX_76802" =~ r1
#=> 0
"221B-Grand View-Dr._El Paso_TX_76802-0000" =~ r1
#=> 0
"2A0B1-Grandview-Dr_Early_ZZ_76802" =~ r1
#=> 0
"201-GrandView-Dr_Early_TX_76802" =~ r1
#=> nil
"201-Grandview-Dr_Early_TX_7680" =~ r1
#=> nil
"201-Pi11ar-St_Early_TX_76802" =~ r1
#=> nil
"I live at 201-Grandview-Dr_Early_TX_76802" =~ r1
#=> nil
"201-mg Circle-Lane_Early_TX_76802" =~ r1
#=> nil
现在考虑第二个为此应该有一个匹配的字符串,例如:
"/50-Washington-St"
我们看到了正则表达式这简直是
r2 =/
\A
\/
#{number}
-
#{street}
-
#{suffix}
\z
/x
#=>/
# \A
# \/
# (?-mix:[[:alnum:]]+)
# -
# (?-mix:[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*)
# -
# (?-mix:[[:upper:]][[:lower:]]+\.?)
# \z
# /x
让我们试试吧。
"/50-Washington-St" =~ r2
#=> 0
"50-Washington-St" =~ r2
#=> nil
"/50-Washington-St_Early" =~ r2
#=> nil
所以,现在我们的整体正则表达式是简单
r = Regexp.union(r1,r2)
#=> /(?x-mi:
# \A # match start of string
# (?-mix:[[:alnum:]]+)
# -
# (?-mix:[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*)
# -
# (?-mix:[[:upper:]][[:lower:]]+\.?)
# _
# (?-mix:[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*)
# _
# (?-mix:[[:upper:]]{2})
# _
# (?-mix:\d{5}(?:-\d{4})?)
# \z # match end of string
# )|(?x-mi:
# \A
# \/
# (?-mix:[[:alnum:]]+)
# -
# (?-mix:[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*)
# -
# (?-mix:[[:upper:]][[:lower:]]+\.?)
# \z
# )/
"201-Grandview-Dr_Early_TX_76802" =~ r
#=> 0
"/50-Washington-St" =~ r
#=> 0
什么是规则,模式? –
你想要匹配什么? –
@NickolayKondratenko我想匹配这两个字符串。即带有连字符的字符串,也带有下划线和末尾的数字字符串 – rubyist