Ruby 的 Regex 的特殊寫法

hmm…其實這篇是給我自己的 memo X"D…有寫起來就比較不會忘,這邊的簡單的不講太多

一般來說 String 做 regex 大概就是 match ( 判斷是否符合 ) & scan ( 挑選 ) 差別如下

"hihihi".match(/(hi)/).to_a  #=> ["hi", "hi"]
"hihihi".match(/(hi)+/).to_a #=> ["hihihi", "hi"]
"hihihi".scan(/(hi)/)  #=> [["hi"], ["hi"], ["hi"]]
"hihihi".scan(/(hi)+/) #=> [["hi"]]

只需要記得 match 擅長於一次性的挑選或檢查是否符合格式,類似檢查身份證字號就可以拿 match 來做,而 scan 擅長於一個大的 string 內挑出很多小部分你要的東西,而不擅長於檢查是否符合格式就是(當然你可以把挑不到的當作檢查手段的一種)

而有一些有趣的東西,原文來自

http://ruby-doc.org/core-2.1.1/Regexp.html

之前的用法都是

string.method(regex)

但其實 regex 可以反過來用

regex.method(string)

然後還可以有更多有趣的寫法,類似

temp = /(?<積>積+)(?<陰>陰+)(?<德>德+)/.match('積陰德')
temp[:積] #=> "積"
temp = /(?<積>積+)(?<陰>陰+)(?<德>德+)/.match('積積陰陰德')
temp[:陰] #=> "陰陰"
temp.class #=> MatchData

這邊就可以完成很漂亮類似 hash 的東西出來,不過其實他不是 hash,而是 regex 專用的物件:回傳結果,缺點是進去的名稱一定會變成 symbol 且只能餵 symbol,而 symbol 會存在記憶體內,在運行的週期內永遠不釋放之類的,然而你在 regex 那邊看到這語法,也可以改在一般的 string match 上玩看看

"積積陰陰德".match(/(?<積>積+)(?<陰>陰+)(?<德>德+)/)
temp[:德] #=> "德"

看來還不錯,繼續換 scan 玩看看

"積積陰陰德".scan(/(?<積>積)/)
#=> [["積"], ["積"]]
"積積陰陰德".scan(/(積)/)
#=> [["積"], ["積"]]
"積積陰陰德".scan(/積/)
#=> ["積", "積"]

所以 scan 是沒作用的,這邊可以當作是 match 專用的語法就是,而( )內的寫法有一定的格式,類似

(?<你要的名稱>原先的regex)

就能得到上面的結果,繼續,下一個就糟糕透了

/(?<積>積+)(?<陰>陰+)(?<德>德+)/ =~ "積積陰陰德"
#=> 0
積 #=> "積積"
陰 #=> "陰陰"
德 #=> "德"

嗯,我第一次看到這個時也感覺…WTF…看來不要常用就是,因為比 symbol 還慘,直接變成區域變數,不過…這說不定比 symbol 還好!?因為區域變數會自動釋放掉,這邊可以做一個實驗,Ruby 可以非常方便的取得 symbol 列表,類似

def test_me(string)
  /(?<敲>敲+)/ =~ string
end
temp('敲可愛') #=> 0

敲 #=> NameError

Symbol::all_symbols #=> [ ..., :積, :陰, :德, :敲]

嗯,看來還是不舒服的啊,so~ 以上,這票雖然很有趣很惡搞,但是請在收斂的狀況下使用,不然…可能會有意想不到的結果就是