2013-01-25 47 views
3

我想寫一個正則表達式來匹配一組字符而不考慮順序。例如:如何編寫一個正則表達式,以任意順序匹配字符?

str = "act" 
str.scan(/Insert expression here/) 

將匹配:

cat 
act 
tca 
atc 
tac 
cta 

但是不匹配caaccata

我在StackOverflow上閱讀了很多類似的問題和答案,但沒有找到完全符合我的目標的問題。

爲了澄清一下,我使用了ruby,並且不想允許重複字符。

+0

我可以澄清一下,你想找到貓,在一個字符串「貓att行爲,ccc」行事。或者你想檢查一下「貓」,「行爲」是行爲的排列嗎? – nhahtdh

+0

只要注意,如果您正在嘗試查找某個字符集合的排列子字符串,則正則表達式不是解決方案。 – nhahtdh

+0

我希望正則表達式能夠匹配重複字符的任何行爲排列和必須使用所有字符的要求。 – Mutuelinvestor

回答

3

這裏是您的解決方案

^(?:([act])(?!.*\1)){3}$ 

看到它here on Regexr

^     # matches the start of the string 
    (?:   # open a non capturing group 
     ([act]) # The characters that are allowed and a capturing group 
     (?!.*\1) # That character is matched only if it does not occur once more, Lookahead assertion 
    ){3}   # Defines the amount of characters 
$ 

唯一特別的想這是lookahead assertion,以確保字符不重複。

^$是錨匹配的字符串的開始和結束。

3

[act]{3}^[act]{3}$會在大多數正則表達方言中使用它。如果你可以縮小你正在使用的系統,這將幫助你得到更具體的答案。

編輯:正如@georgydyer在下面的評論中提到的那樣,從您的問題中不清楚是否允許重複字符。如果沒有,你可以從this question適應的答案,得到:

^(?=[act]{3}$)(?!.*(.).*\1).*$ 

也就是說,正向前查找,檢查匹配,然後用反向引用一個負向前查找,排除重複的字符。

+0

但是,這也會匹配任何字符重複,例如aaa,aac,att,對嗎? – georgedyer

+2

是的,會的。重讀這個問題讓我不清楚這是否允許。如果不是,問題是http://stackoverflow.com/questions/3101366/regex-to-match-1234-1324-2341-all-permutations-of-1-2-3-4的重複,並且接受的答案應該可以正常工作。 –

+1

那裏的解決方案只適用於一組字符的排列,並且不適用於多重集。另一件事就是這麼多'^(?= [act] {3} $)(?!。*(。)。* \ 1)'足夠。 – nhahtdh

1

我將在這裏假設幾件事情: - 您正在尋找給定的字符 的排列 - 您正在使用紅寶石

str = "act" 
permutations = str.split(//).permutation.map{|p| p.join("")} 

# and for the actual test 
permutations.include?("cat") 

這不是正則表達式雖然。

+0

你想通過排列輸入字符串來做什麼? – nhahtdh

+0

correkt匹配給出的例子是輸入字符的排列:cat act tca atc​​ tac cta – scones

1

毫無疑問 - 使用積極/消極的前瞻和反向引用的正則表達式是光滑的,但如果你只處理三個字符,我會在明確列舉像@scones這樣的字符排列方面犯錯。

"act".split('').permutation.map(&:join) 
=> ["act", "atc", "cat", "cta", "tac", "tca"] 

如果你真的需要一個正則表達式出來的用於掃描較大的字符串,可以隨時:

Regexp.union "act".split('').permutation.map(&:join) 
=> /\b(act|atc|cat|cta|tac|tca)\b/ 

顯然,如果你的搜索字符串增長這一戰略並沒有形成規模,但它的在我看來,更容易觀察這樣的代碼的意圖。

編輯:基於@inTinMan的反饋,在cata上添加了用於假陽性的字邊界。

+0

更好地檢查你的工作。 –

+0

@theTinMan這是來自irb的複製/粘貼輸出。你能否對你認爲存在問題的地方不那麼神祕? – Cade

+0

根據OP的命中和錯過單詞列表測試您的正則表達式。 –

2

這是我怎麼會去一下吧:

regex = /\b(?:#{ Regexp.union(str.split('').permutation.map{ |a| a.join }).source })\b/ 
# => /(?:act|atc|cat|cta|tac|tca)/ 

%w[ 
    cat act tca atc tac cta 
    ca ac cata 
].each do |w| 
    puts '"%s" %s' % [w, w[regex] ? 'matches' : "doesn't match"] 
end 

輸出:

"cat" matches 
"act" matches 
"tca" matches 
"atc" matches 
"tac" matches 
"cta" matches 
"ca" doesn't match 
"ac" doesn't match 
"cata" doesn't match 

我用傳遞一個數組Regexp.union對很多東西的技術;我特別適合使用散列鍵,並將散列傳遞到gsub以快速搜索/替換文本模板。這是從gsub文檔的例子:

'hello'.gsub(/[eo]/, 'e' => 3, 'o' => '*') #=> "h3ll*" 

Regexp.union創建一個正則表達式,並提取所產生的實際模式時使用source而不是to_s是很重要的:

puts regex.to_s 
=> (?-mix:\b(?:act|atc|cat|cta|tac|tca)\b) 

puts regex.source 
=> \b(?:act|atc|cat|cta|tac|tca)\b 

注意如何to_s嵌入模式的字符串內的標誌。如果你不指望它們,你可能會意外地將該模式嵌入到另一個模式中,這不會像你期望的那樣運行。在那裏,做到了這一點,並有凹下的頭盔作爲證明。

如果您真的想獲得樂趣,請查看CPAN上提供的Perl Regexp::Assemble模塊。使用它,再加上List::Permutor,可以讓我們生成更復雜的模式。就像這樣一個簡單的字符串,它不會節省太多的空間,但是對於長字符串或大陣列的期望命中,它可以產生巨大的差異。不幸的是,Ruby有這樣的事,但它是可以寫的字或詞的數組一個簡單的Perl腳本,有它產生的正則表達式,並將其傳遞迴:

use List::Permutor; 
use Regexp::Assemble; 

my $regex_assembler = Regexp::Assemble->new; 
my $perm = new List::Permutor split('', 'act'); 
while (my @set = $perm->next) { 
    $regex_assembler->add(join('', @set)); 
} 
print $regex_assembler->re, "\n"; 
(?-xism:(?:a(?:ct|tc)|c(?:at|ta)|t(?:ac|ca))) 

請參閱「Is there an efficient way to perform hundreds of text substitutions in Ruby?」更多有關使用Regexp :: Assemble with Ruby的信息。

+0

作爲一個通用的解決方案,爲了找到所有匹配,我寧願使用滑動窗口和循環而不是正則表達式。 – nhahtdh

+0

這是一個不錯的主意,但是一個正則表達式會大大超出循環,如果正確完成,可以告訴你正則表達式匹配的值。 –

+0

滑動窗口也可以告訴子串的開始和結束位置,所以功能明智,都應該是相同的。 (保持開始和結束位置很可能是在正則表達式引擎中完成的)。性能有點有問題。 – nhahtdh

相關問題