我想寫一個正則表達式來匹配一組字符而不考慮順序。例如:如何編寫一個正則表達式,以任意順序匹配字符?
str = "act"
str.scan(/Insert expression here/)
將匹配:
cat
act
tca
atc
tac
cta
但是不匹配ca
,ac
或cata
。
我在StackOverflow上閱讀了很多類似的問題和答案,但沒有找到完全符合我的目標的問題。
爲了澄清一下,我使用了ruby,並且不想允許重複字符。
我想寫一個正則表達式來匹配一組字符而不考慮順序。例如:如何編寫一個正則表達式,以任意順序匹配字符?
str = "act"
str.scan(/Insert expression here/)
將匹配:
cat
act
tca
atc
tac
cta
但是不匹配ca
,ac
或cata
。
我在StackOverflow上閱讀了很多類似的問題和答案,但沒有找到完全符合我的目標的問題。
爲了澄清一下,我使用了ruby,並且不想允許重複字符。
這裏是您的解決方案
^(?:([act])(?!.*\1)){3}$
^ # 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,以確保字符不重複。
^
和$
是錨匹配的字符串的開始和結束。
[act]{3}
或^[act]{3}$
會在大多數正則表達方言中使用它。如果你可以縮小你正在使用的系統,這將幫助你得到更具體的答案。
編輯:正如@georgydyer在下面的評論中提到的那樣,從您的問題中不清楚是否允許重複字符。如果沒有,你可以從this question適應的答案,得到:
^(?=[act]{3}$)(?!.*(.).*\1).*$
也就是說,正向前查找,檢查匹配,然後用反向引用一個負向前查找,排除重複的字符。
但是,這也會匹配任何字符重複,例如aaa,aac,att,對嗎? – georgedyer
是的,會的。重讀這個問題讓我不清楚這是否允許。如果不是,問題是http://stackoverflow.com/questions/3101366/regex-to-match-1234-1324-2341-all-permutations-of-1-2-3-4的重複,並且接受的答案應該可以正常工作。 –
那裏的解決方案只適用於一組字符的排列,並且不適用於多重集。另一件事就是這麼多'^(?= [act] {3} $)(?!。*(。)。* \ 1)'足夠。 – nhahtdh
毫無疑問 - 使用積極/消極的前瞻和反向引用的正則表達式是光滑的,但如果你只處理三個字符,我會在明確列舉像@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
上添加了用於假陽性的字邊界。
更好地檢查你的工作。 –
@theTinMan這是來自irb的複製/粘貼輸出。你能否對你認爲存在問題的地方不那麼神祕? – Cade
根據OP的命中和錯過單詞列表測試您的正則表達式。 –
這是我怎麼會去一下吧:
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的信息。
我可以澄清一下,你想找到貓,在一個字符串「貓att行爲,ccc」行事。或者你想檢查一下「貓」,「行爲」是行爲的排列嗎? – nhahtdh
只要注意,如果您正在嘗試查找某個字符集合的排列子字符串,則正則表達式不是解決方案。 – nhahtdh
我希望正則表達式能夠匹配重複字符的任何行爲排列和必須使用所有字符的要求。 – Mutuelinvestor