# 11正則表達式
### 使用 Heregexes
### 問題
你需要寫一個復雜的正則表達式。
### 解決方案
使用 CoffeeScript 的 “heregexes” ——可以忽視內部空白字符并可以包含注釋的擴展正則表達式。
~~~
pattern = ///
^\(?(\d{3})\)? # 采集區域代碼,忽略可選的括號
[-\s]?(\d{3}) # 采集前綴,忽略可選破折號或空格
-?(\d{4}) # 采集行號,忽略可選破折號
///
[area_code, prefix, line] = "(555)123-4567".match(pattern)[1..3]
# => ['555', '123', '4567']
~~~
### 討論
通過打破復雜的正則表達式和注釋重點部分,它們變得更加容易去辨認和維護。例如,現在這是一個相當明顯的做法去改變正則表達式以容許前綴和行號之間存在可選的空間。
### heregexes 中的空白字符
空白字符在 heregexes 中是被忽視的——所以如果要為 ASCII 空格匹配字符,你應該怎么做呢?
我們的解決方案是使用 @\s@ 字符組,它能夠匹配空格,制表符和換行符。假如你只想匹配一個空格,你需要使用 \X20 來表示字面上的 ASCII 空格。
### 使用 HTML 命名實體替換 HTML 標簽
### 問題
你需要使用命名實體來替代 HTML 標簽:
`<br/> => <br/>`
### 解決方案
~~~
htmlEncode = (str) ->
str.replace /[&<>"']/g, ($0) ->
"&" + {"&":"amp", "<":"lt", ">":"gt", '"':"quot", "'":"#39"}[$0] + ";"
?
htmlEncode('<a href="http://bn.com">Barnes & Noble</a>')
# => '<a href="http://bn.com">Barnes & Noble</a>'
~~~
### 討論
可能有更好的途徑去執行上述方法。
### 替換子字符串
### 問題
你需要用另一個值替換字符串的一部分。
### 解決方案
使用 JavaScript 的 **replace** 方法。它與給定字符串匹配,并返回已編輯的字符串。
第一個版本需要 2 個參數:*模式*和*字符串替換*
~~~
"JavaScript is my favorite!".replace /Java/, "Coffee"
# => 'CoffeeScript is my favorite!'
?
?
"foo bar baz".replace /ba./, "foo"
# => 'foo foo baz'
?
?
"foo bar baz".replace /ba./g, "foo"
# => 'foo foo foo'
~~~
第二個版本需要 2 個參數:*模式*和*回調函數*
~~~
"CoffeeScript is my favorite!".replace /(\w+)/g, (match) ->
match.toUpperCase()
# => 'COFFEESCRIPT IS MY FAVORITE!'
~~~
每次匹配需要調用回調函數,并且匹配值作為參數傳給回調函數。
### 討論
正則表達式是一種強有力的方式來匹配和替換字符串。
### 查找子字符串
### 問題
你需要搜索一個字符串,并返回匹配的起始位置或匹配值本身。
### 解決方案
有幾種使用正則表達式的方法來實現這個功能。其中一些方法被稱為 RegExp 模式或對象還有一些方法被稱為 String 對象。
#### RegExp 對象
第一種方式是在 RegExp 模式或對象中調用 test 方法。test 方法返回一個布爾值:
~~~
match = /sample/.test("Sample text")
# => false
?
?
match = /sample/i.test("Sample text")
# => true
~~~
下一種方式是在 RegExp 模式或對象中調用 exec 方法。exec 方法返回一個匹配信息的數組或空值:
~~~
match = /s(amp)le/i.exec "Sample text"
# => [ 'Sample', 'amp', index: 0, input: 'Sample text' ]
?
?
match = /s(amp)le/.exec "Sample text"
# => null
~~~
#### String 對象
match 方法使給定的字符串與表達式對象匹配。有 “g” 標識的返回一個包含匹配項的數組,沒有 “g” 標識的僅返回第一個匹配項或如果沒有找到匹配項則返回 null 。
~~~
"Watch out for the rock!".match(/r?or?/g)
# => [ 'o', 'or', 'ro' ]
?
?
"Watch out for the rock!".match(/r?or?/)
# => [ 'o', index: 6, input: 'Watch out for the rock!' ]
?
?
"Watch out for the rock!".match(/ror/)
# => null
~~~
search 方法以字符串匹配正則表達式,且如果找到的話返回匹配的起始位置,未找到的話則返回 -1 。
~~~
"Watch out for the rock!".search /for/
# => 10
?
?
"Watch out for the rock!".search /rof/
# => -1
~~~
### 討論
正則表達式是一種可用來測試和匹配子字符串的強大的方法。