2012-07-31 38 views
0

我有以下的正則表達式和函數來提取電子郵件到一個數組,而它的工作對我來說似乎並不理想。任何關於我如何批准此事的建議?從字符串中提取電子郵件的更紅寶石般的方式?

@emails = [] 
matches = @text_document.scan(/\+'(\[email protected]\S+|\{(?:\w+, *)+\w+\}@[\w.-]+)'/i) 
matches.each {|m| m[0].split(',').each {|email| @emails << email } } 

具體我正在尋找的東西比嵌套each'es更好。

乾杯

編輯要完全公平的,因爲我很喜歡這兩個答案,我給他們倆一個公平運行,但由於CONCAT稍快,縮短我將標誌着作爲回答。

require 'benchmark' 

CONSTANT = 1 
BenchTimes = 1_000_000 
EMAILS = "+'[email protected],[email protected]'" 

def email 
end 

def bm_concat 
    emails = [] 
    EMAILS.scan(/\+'(\[email protected]\S+|\{(?:\w+, *)+\w+\}@[\w.-]+)'/i) do |matches| 
    matches.each {|m| emails.concat(m.split(','))} 
    end 

end 

def bm_inject 
    emails = [] 
    EMAILS.scan(/\+'(\[email protected]\S+|\{(?:\w+, *)+\w+\}@[\w.-]+)'/i) do |matches| 
    matches.inject([]) {|arr, mails| emails.concat(mails.split(',')) } 
    end 

end 

Benchmark.bmbm do |bm| 
    bm.report("inject:") { BenchTimes.times { bm_inject } } 
    bm.report("concat:") { BenchTimes.times { bm_concat } } 
end 

產生以下的輸出:

Rehearsal ------------------------------------------- 
inject: 11.030000 0.060000 11.090000 (11.145898) 
concat: 9.660000 0.050000 9.710000 ( 9.761068) 
--------------------------------- total: 20.800000sec 

       user  system  total  real 
inject: 11.620000 0.060000 11.680000 (11.795601) 
concat: 10.510000 0.050000 10.560000 (10.678999) 
+3

[不要用正則表達式做(http://stackoverflow.com/questions/201323/using-a-regular-expression-到驗證-的電子郵件地址)。 – Polynomial 2012-07-31 14:09:09

+0

@Polynomial:這個鏈接的電子郵件正則表達式是*可怕的*。我不想成爲圖書館的維護者。 – Linuxios 2012-07-31 14:18:44

+1

同意。找一個圖書館,或者只是希望你沒有像'hGy∂@olé.museum'這樣的地址。 – Linuxios 2012-07-31 14:22:10

回答

1

可以重構matches.each這樣:

matches.each {|m| @emails.concat(m[0].split(','))} 
+0

我並不擔心這個正則表達式,它是matches.each(| m | m [0] .split(',')。 – mhenrixon 2012-07-31 15:23:26

+1

這實現了RFC822/RFC2822電子郵件規範,它也將很多標記爲「有效」,被某些郵件系統拒絕,因爲它們「理論上*你可以在你的電子郵件地址中有空格,但是我從來沒有在實踐中看到過這種情況,甚至一次都沒有見過這樣的情況 – tadman 2012-07-31 15:57:33

+0

@mhenrixon:擺脫驗證並給你一個解決方案 – Linuxios 2012-07-31 23:01:22

1

使用注射 - http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject

@emails = matches.inject([]) do |emails, input| 
    emails += input.first.split(',') 
end 

僅供參考,變量過時d到塊,電子郵件是指傳入的空數組,並且輸入是指在迭代它時每個匹配元素。

編輯(如何使用注射):

REGEX = /\+'(\[email protected]\S+|\{(?:\w+, *)+\w+\}@[\w.-]+)'/i 
def bm_inject 
    emails = EMAILS.scan(REGEX).inject([]) do |arr, mails| 
    arr.concat mails.first.split(',') 
    end 
end 
+0

當然,你也可以在一條線上用花括號 – AJcodez 2012-07-31 16:27:56

+0

謝謝你的提示!我給了它一個公平的運行,但由於@Linuxios解決方案稍快,這將被標記爲答案。 – mhenrixon 2012-08-01 09:18:36

+1

良好的基準調用。 Id敦促您重新訪問注入文檔並查看我的編輯,以便您瞭解未來,因爲您錯誤地使用它! – AJcodez 2012-08-01 21:11:53