昨天的重點複習/./
就是一個最簡單的正規表達式。
match
與=~
。match
回傳匹配的內容。=~
回傳匹配的位置。
2.7.3 :195 > /abc/.match("hello abc here abc")
=> #<MatchData "abc">
2.7.3 :196 > /abc/.match?("hello abc here abc")
=> true
#把檢查對象內符合表達式的內容,回傳出來。
2.7.3 :197 > /abc/ =~ "hello abc here abc"
=> 6
2.7.3 :198 > /bca/ =~ "hello abc here abc"
=> nil
2.7.3 :199 > /./ =~ "hello abc here abc"
=> 0
2.7.3 :204 > "hello abc here abc"[6]
=> "a"
#回傳符合的位置的index,當然0才是第一個。如果檢查對象內有兩個,只回傳第一個。
()
。當需要檢測或找出的資料有兩組的例子。
2.7.3 :006 > /(Rails).*(easy)/.match("Do you like Rails? It so easy!")
=> #<MatchData "Rails? It so easy" 1:"Rails" 2:"easy">
.*
先暴雷,*
代表有0或多個。
2.7.3 :007 > $1
=> "Rails"
2.7.3 :008 > $2
=> "easy"
可以看到用$
可以呼叫出匹配到的資料,有n組就可以到$n
。
開始認識那些鬼畫符。
+
、 ?
、 .
、 *
、 ^
、 $
、 ()
、 []
、 { }
、 |
、 \
。
以上都代表有特殊功能,.
是代表任何一個字前面示範已充足展示,如果當想表達這些符號出來,都是利用\
來處理。
2.7.3 :009 > /(\?).*(easy)/.match("Do you like Rails? It so easy!")
=> #<MatchData "? It so easy" 1:"?" 2:"easy">
2.7.3 :010 > /(?).*(easy)/.match("Do you like Rails? It so easy!")
Traceback (most recent call last): undefined group option: /(?).*(easy)/ (SyntaxError)
2.7.3 :011 > /..\?../.match("Do you like Rails? It so easy!")
=> #<MatchData "ls? I">
*
:0或多次。+
:1或多次。 兩兄弟,一起示範。
2.7.3 :013 > /.*\?/.match("?")
=> #<MatchData "?">
2.7.3 :014 > /.*\?/.match("Date?")
=> #<MatchData "Date?">
2.7.3 :016 > /.+\?/.match("Date?")
=> #<MatchData "Date?">
2.7.3 :017 > /.+\?/.match("?")
=> nil
#如果?號前面沒有字元出現過至少一個就抓不到了。
{n}
:指定n次。
2.7.3 :047 > /.*/.match("hello world")
=> #<MatchData "hello world">
2.7.3 :048 > /.{5}/.match("hello world")
=> #<MatchData "hello">
2.7.3 :049 > /.{3}/.match("hello world")
=> #<MatchData "hel">
{n,}
:n次或更多。
2.7.3 :053 > /a{3,}/.match("a")
=> nil
2.7.3 :054 > /a{3,}/.match("aaa")
=> #<MatchData "aaa">
2.7.3 :055 > /a{3,}/.match("aaaaaaaaa")
=> #<MatchData "aaaaaaaaa">
{,m}
:m次或更少次。
2.7.3 :056 > /a{,3}/.match("aaaaaaaaa")
=> #<MatchData "aaa">
2.7.3 :057 > /a{,3}/.match("aa")
=> #<MatchData "aa">
2.7.3 :058 > /a{,3}/.match("a")
=> #<MatchData "a">
{n,m}
:最少n次,最多m次。
2.7.3 :059 > /a{2,3}/.match("a")
=> nil
2.7.3 :060 > /a{2,3}/.match("aa")
=> #<MatchData "aa">
2.7.3 :061 > /a{2,3}/.match("aaaaa")
=> #<MatchData "aaa">
?
:本身為0或1次,常與其他語法搭配。簡單一點理解,量詞加上?
之後以執行最少次優先(非貪婪)。
2.7.3 :068 > /a?/.match?("cde")
=> true #0次匹配到也ok
2.7.3 :069 > /a/.match?("cde")
=> false
2.7.3 :062 > /a{3,}?/.match("aaaaaaaaa")
=> #<MatchData "aaa">
2.7.3 :063 > /a{3,}/.match("aaaaaaaaa")
=> #<MatchData "aaaaaaaaa">
量詞都以貪婪
優先,盡可能去匹配,但加上?
就是非貪婪,另外+
在量詞後也有另外的效果。
/a.*b/
假設有一個表達式是這樣,當我們去match``"a123b123123"
時,會先抓到a
後,會開始匹配.*
,而整段字串都符合.*
,所以其實會先記憶住a123b123123
,而當繼續匹配b
時,被記憶住的a123b123123
,會3``2``1``3``2``1
這樣釋放出來到b
為止。
而當量詞加上+
後,會不允許這樣的行為,將a123b123123
記憶住不回朔。
整理一下
`*`:0或多次。
`+`:1或多次。
`?`:0或1次。
`{n}`:指定n次。
`{n,}`:n次或更多。
`{,m}`:m次或更少次。
`{n,m}`:最少n次,最多m次。
網路上看到一些資料寫re+
、re*
,想半天也想不出這是什麼,其實就是量詞。RE
是Regular Expression
的縮寫,re*
等於是指一段regexp
重複0或多次。
^
:匹配於行首。$
:匹配於行尾。
2.7.3 :111 > /^ruby/.match("gogo ruby, fight ruby")
=> nil
2.7.3 :112 > /^ruby/.match("ruby gogo , fight ruby")
=> #<MatchData "ruby">
#不是在行首就匹配不到。
2.7.3 :115 > /ruby$/.match("ruby gogo , fight ruby")
=> #<MatchData "ruby">
2.7.3 :116 > /ruby$/.match("ruby gogo , ruby fight")
=> nil
#記得$在後。
\A
:匹配開頭"字串",不包括\n
後的位置。\Z
:匹配结尾"字串"。可以是\n
前的位置,也可以是絕對结尾。\z
:匹配结尾"字串",允許包括\n
,即字符串的絕對结尾。看code比較快
2.7.3 :194 > "\nruby love you".match(/^ruby/)
=> #<MatchData "ruby">
2.7.3 :195 > "\nruby love you".match(/\Aruby/)
=> nil
2.7.3 :196 > "ruby love you".match(/\Aruby/)
=> #<MatchData "ruby">
#\A與^感覺上\A更精準,有絕對行首的意思在。
2.7.3 :210 > "you love ruby\n".match(/ruby$/)
=> #<MatchData "ruby">
2.7.3 :211 > "you love \nruby".match(/ruby$/)
=> #<MatchData "ruby">
2.7.3 :212 > "you love ruby\n".match(/ruby\Z/)
=> #<MatchData "ruby">
2.7.3 :213 > "you love \nruby".match(/ruby\Z/)
=> #<MatchData "ruby">
2.7.3 :214 > "you love \nruby".match(/ruby\z/)
=> #<MatchData "ruby">
2.7.3 :215 > "you love ruby\n".match(/ruby\z/)
=> nil
#\Z與$ 沒有差太多,\z明顯更精準。
這邊先不要太去care分別,用多了自然會知道該用哪種。
\b
:明確抓出單詞時用。\B
:抓出單詞,但一邊不用明確時用。感覺自己不像在講國語!!!
2.7.3 :230 > /ruby/.match("iloverubyloveyou")
=> #<MatchData "ruby">
2.7.3 :231 > /\bruby\b/.match("iloverubyloveyou")
=> nil
2.7.3 :232 > /\bruby\b/.match("ilove ruby loveyou")
=> #<MatchData "ruby">
#單字的"邊界"
2.7.3 :233 > /\bruby\B/.match("rubyloveyou")
=> #<MatchData "ruby">
2.7.3 :234 > /\Bruby\b/.match("rubyloveyou")
=> nil
2.7.3 :235 > /\Bruby\b/.match("iloveruby")
=> #<MatchData "ruby">
2.7.3 :236 > /\Bruby\B/.match("iloverubyloveyou")
=> #<MatchData "ruby">
#沒意義
整理
`^`:匹配於行首。
`$`:匹配於行尾。
`\A`:匹配開頭"字串",不包括`\n`後的位置。
`\Z`:匹配结尾"字串"。可以是`\n`前的位置,也可以是絕對结尾。
`\z`:匹配结尾"字串",允許包括`\n`,即字符串的絕對结尾。
`\b`:這樣記,明確抓出單詞時用。
`\B`:抓出單詞,但一邊不用明確時用。
講到這又篇幅過大了...
今天再認識一些特殊用法
/(?=!)/
:有一個!
才匹配。
2.7.3 :244 > /ruby(?=!)/.match("ruby")
=> nil
2.7.3 :245 > /ruby(?=!)/.match("ruby!")
=> #<MatchData "ruby">
2.7.3 :246 > /ruby(?=!)/.match("iloveruby")
=> nil
2.7.3 :247 > /ruby(?=!)/.match("iloveruby!")
=> #<MatchData "ruby">
/(?!!)/
:沒有!
才匹配。
2.7.3 :248 > /ruby(?!!)/.match("iloveruby!")
=> nil
2.7.3 :249 > /ruby(?!!)/.match("iloveruby")
=> #<MatchData "ruby">
(?i)
:R後面的資料不分大小寫。
2.7.3 :253 > /R(?i)uby/.match("RUBY")
=> #<MatchData "RUBY">
2.7.3 :254 > /R(?i)uby/.match("Ruby")
=> #<MatchData "Ruby">
2.7.3 :255 > /Ruby/.match("RUBY")
=> nil
/bbb|aaa/
:or
(給易拼錯字的人用)。
2.7.3 :256 > /model|modle/.match("rails g modle Rail")
=> #<MatchData "modle">
2.7.3 :257 > /model|modle/.match("rails g modle Rail model")
=> #<MatchData "modle">
/mod(le|el)
:內部or
(給易拼錯字的人用)。
2.7.3 :258 > /mod(el|le)/.match("rails g modle Rail")
=> #<MatchData "modle" 1:"le">
#用|會紀錄最先抓到的。
好像突然知道,為何Rails常有提醒我打錯字了?
/(!+|\?)/
:匹配有多!
個或一個?
。
2.7.3 :267 > /ruby(!+|\?)/.match("ruby!!!!! ruby?")
=> #<MatchData "ruby!!!!!" 1:"!!!!!">
明天就可以開始解決任何原本看不懂的天書了o 0!
今天的leetcode345. Reverse Vowels of a String
題目連結:https://leetcode.com/problems/reverse-vowels-of-a-string/
題目重點:又是一題用正規表達式會很好解的。
gsub
有四種用法,除了像昨天輸入兩個參數後,會把字串裡指定的值(第一個參數),換成第二個參數。
2.7.3 :017 > "hello".gsub("l", "a")
=> "heaao"
還有只帶一個參數的話,可以成為枚舉器(迭代器)。
2.7.3 :017 > "hello".gsub("l", "a")
=> "heaao"
2.7.3 :018 > "hello".gsub("l")
=> #<Enumerator: ...>
2.7.3 :019 > "hello".gsub("l") {puts "抓到幾個,替換幾個"}
抓到幾個,替換幾個
抓到幾個,替換幾個
=> "heo"
2.7.3 :020 > "hello".gsub("l") { "a" }
=> "heaao"
因為這題要我們將aeiou的所在位置reverse
。
abci => ibca
abeci => ibeca
那我們先將母音的值與順序抓出來。
2.7.3 :021 > "hello".scan(/[aeiou]/i)
=> ["e", "o"]
如果gsub(/[aeiou]/i) { }
的block
裡可以將["e", "o"]
由後一一提供的話,那就可以替換完成了。pop
2.7.3 :022 > x = ["a", "b", "c"]
=> ["a", "b", "c"]
2.7.3 :023 > x.pop
=> "c"
2.7.3 :024 > x
=> ["a", "b"]
2.7.3 :025 > x.pop
=> "b"
2.7.3 :026 > x
=> ["a"]
2.7.3 :027 > x.pop
=> "a"
def reverse_vowels(s)
vowels = s.scan(/[aeiou]/i)
s.gsub(/[aeiou]/i) { vowels.pop }
end
完成!