2012-11-13 48 views
1

我想在我的Rails應用程序中創建一個動態正則表達式。我在我的數據庫中有一個名爲foo的表。 foo由兩列組成,即idphrase,它們只是varchar(255)。我希望能夠使所有'短語'實例都加入一個巨大的表達式,並看看傳入的參數是否與短語中的任何單詞匹配。我認爲像下面這樣的東西可能會這樣做,但它似乎並不適用。我究竟做錯了什麼?Ruby中的正則表達式動態創建

# get all phrases 
phrases = Foo.all.map(&:phrase) 

regex = Regexp.new phrases.join('|') 

if params[:some_text] =~ regex 
    # something in params[:some_text] matched at least one phrase 
end 
+0

爲什麼不只是''Foo.where(:phrase => params [:some_text])。present?' –

+0

因爲如果''params [:some_text] ==「Hello World」'和短語只是'世界',它不會起作用。 – randombits

+0

什麼不適合你? –

回答

1

你想用Regexp.union

聯盟(PAT1,PAT2,...)→new_regexp
聯盟(pats_ary)→new_regexp

返回Regexp對象,給定模式的聯合,即,將匹配其任何部分。模式可以是Regexp對象,在這種情況下,它們的選項將被保留,或String s。

所以才這樣的:

regex = Regexp.union(phrases) 

例如:

>> phrases = %w[pancakes egg$] 
=> ["pancakes", "egg$"] 
>> puts Regexp.new(phrases.join('|')).inspect 
/pancakes|egg$/ 
>> puts Regexp.union(phrases).inspect 
/pancakes|egg\$/ 

注意在union版的逃脫$。還有Regexp.quote(AKA Regexp.escape),如果您需要選擇性地轉義特定的字符串。一般來說,你不想只將一堆隨機字符串混合在一起構建一個正則表達式,正則表達式語法字符每次都會得到你;使用Regex.union進行大的改動,或在將它們放在一起之前通過Regex.escape發送你的作品。

你也可以做一個LIKE查詢,如果你想保持它的數據庫中:

Foo.where('phrase like ?', "%#{params[:some_text]}%") 

或者完全跳過所有的模式匹配的東西,它的逃避問題,並做了簡單的字符串位置檢查:

Foo.where('position(? in phrase) != 0', params[:some_text]) 

這兩個都會進行表掃描,但您的Foo.all也是如此。

+0

完美!非常感謝 – randombits

-1
1.8.7 > phrases = ['one', 'two', 'three'] 
=> ["one", "two", "three"] 
1.8.7 > regex = Regexp.new phrases.join('|') 
=> /one|two|three/ 
1.8.7 > puts 'match' if "a one b" =~ regex 
match 

也許還有別的東西怎麼回事?你正在做的是爲我工作,從等式中刪除AR。

+1

如果'phrase'包含像''string $''這樣的東西,那麼這將失敗,因爲你不能逃脫正則表達式字符。 –