[英]How do I write a regular expression that matches two patterns in any order?
[英]How do I write a regular expression that will match characters in any order?
我正在嘗試編寫一個正則表達式,它將匹配一組字符而不考慮順序。 例如:
str = "act"
str.scan(/Insert expression here/)
會匹配:
cat
act
tca
atc
tac
cta
但不會匹配ca
, ac
或cata
。
我在StackOverflow上閱讀了很多類似的問題和答案,但沒有找到與我的目標完全匹配的問題。
為了澄清一點,我使用ruby並且不想允許重復字符。
這是你的解決方案
^(?:([act])(?!.*\1)){3}$
在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
$
唯一的特殊想法是前瞻性斷言 ,以確保不再重復這個角色。
^
和$
是匹配字符串開頭和結尾的錨點。
[act]{3}
或^[act]{3}$
將在大多數正則表達式方言中執行此操作。 如果您可以縮小您正在使用的系統范圍,那么這將有助於您獲得更具體的答案。
編輯:正如@georgydyer在下面的評論中提到的,從你的問題中不清楚是否允許重復的字符。 如果沒有,你可以調整這個問題的答案,得到:
^(?=[act]{3}$)(?!.*(.).*\1).*$
也就是說,檢查匹配是一個積極的先行,然后是帶有反向引用的負向前瞻以排除重復的字符。
這是我如何去做的:
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
的技術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)))
請參閱“ 有沒有一種有效的方法在Ruby中執行數百個文本替換? ”,以獲取有關在Ruby中使用Regexp :: Assemble的更多信息。
我將在這里假設幾件事: - 你正在尋找給定角色的排列 - 你正在使用紅寶石
str = "act"
permutations = str.split(//).permutation.map{|p| p.join("")}
# and for the actual test
permutations.include?("cat")
但這不是正則表達式。
毫無疑問 - 使用正面/負面前瞻和反向引用的正則表達式是光滑的,但是如果你只處理三個字符,我會通過明確枚舉像@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/
顯然,如果您的搜索字符串增長,這種策略不會擴展,但在我看來,更容易觀察到這樣的代碼的意圖。
編輯 :根據@ theTinMan的反饋為cata
添加了誤報的單詞邊界。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.