Я хотел бы предложить способ решения таких проблем, как этот. Основной вывод заключается в том, что сложные регулярные выражения могут быть построены так же, как и другой код 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
Предположительно регулярное выражение должно мат ch строка, если и только если строка содержит допустимые значения для каждого из этих шести полей и имеет форматирование, показанное между соседними полями.
Начнем с выделения отдельного регулярного выражения для каждого из шести полей. Естественно, что все эти регулярные выражения могут нуждаться в модификации в соответствии с требованиями.
Улица номер
Типичной улица номер может быть "221", "22", "221b". Предположим, у нас также могут быть «A19» или «221BZ», но не «221-B». Тогда мы могли бы написать:
number = /[[:alnum:]]+/
(. Найти "POSIX" в Regexp) Название
Street
я предположил, что названия улиц состоят из одного слова или нескольких слов, разделенных одиночное пространство, где каждое слово имеет все строчные буквы, кроме первой буквы, которая заглавная.
street = /[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*/
/[[:upper:]][[:lower:]]+
соответствует первому слову, (?:\s[[:upper:]][[:lower:]])*
соответствует пробелу, затем заглавным слово, повторяется ноль или более раз ((?:...)
не-захват группа. Задний *
означает повторить ноль или более раз.)
название улицы суффикс
я предположил, что суффикс названия улицы (например, «Улица», «St.«) Является одним словом, все в нижнем регистре, за исключением первого символа, который в верхнем регистре, необязательно заканчивается период:
suffix = /[[:upper:]][[:lower:]]+\.?/
Сити
Я предположил, что названия городов имеет то же самое требования, как сделать название улиц:
city = street
#=> /[[:upper:]][[:lower:]]+(?:\s[[:upper:]][[:lower:]]+)*/
государственного
государств определяются двумя прописными буквами:
state = /[[:upper:]]{2}/
Мы могли бы быть более точным, написав:
state = Regexp.union %w| AL AK AZ ... |
, но тогда нам придется обновлять его каждый раз, когда территория стала новым государством или (возможно, из-за недавних событий) государство отделяется от союза.
Почтовый индекс
Zip коды пять цифр или девять цифр с тире или дефис после первых четырех цифр.
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