2016-11-16 85 views
1

我有一個字符串,如下匹配的正則表達式的紅寶石

201-Grandview-Dr_Early_TX_76802/50-Washington-St

我寫一個正則表達式來匹配兩個字符串。

((/^([0-9]+)-([^_]+)-([A-Za-z]{1,})$/ =~ data) == 0) 

但上述正則表達式只匹配50-Washington-St而不是第二個匹配。

那麼這個正則表達式有什麼問題呢?

琴絃的更新列表應符合:

201-Grandview-Dr_Early_TX_76802 
/50-Washington-St 
49220-Sunrose-Ln_Palm-Desert_CA_92260 
201-Grandview-Dr_Early_TX_76802 
50-Washington-St 
+0

什麼是規則,模式? –

+0

你想要匹配什麼? –

+0

@NickolayKondratenko我想匹配這兩個字符串。即帶有連字符的字符串,也帶有下劃線和末尾的數字字符串 – rubyist

回答

5

您可以修復的正則表達式像

/^\/?([0-9]+)-(.+?)-(\w+)$/ 

或整個(介意^線匹配匹配 start和$以Ruby正則表達式結束):

/\A\/?([0-9]+)-(.+?)-(\w+)\z/ 

Rubular demo

圖案的詳細資料

  • \A - 字符串開頭
  • \/? - 可選/
  • ([0-9]+) - 第1組:一個或多個數字
  • - - 一個 連字符
  • (.+?) - 組2:比換行符字符其他
  • -一個或多個字符 - 連字符
  • (\w+) - 第3組:一個或多個單詞([A-Za-z0-9_])字符
  • \z - 字符串的結尾。
+0

Stribizew但它沒有通過「/ 50-Washington-St」與你的正則表達式 – rubyist

+0

爲什麼要這樣呢?它不像你的問題中的字符串。但是你可以在'^'或'\'之後加''W *'(如果你想在開始時允許任意數量的非單詞字符)或'\ /?'(只允許一個可選的'/' A'。 –

+0

好的。對不起,這是錯字錯誤 – rubyist

0

我想提出一種解決像這樣的問題的方法。主要的任務是可以用與其他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