[英]php regex negative lookahead
我有4個字母的字典。 我想編寫一個正則表達式來瀏覽字典,並匹配給定一組字母的所有單詞。
假設我通過a,b,l,l
。 我想找到所有帶有這些字母的單詞。
我知道我可以做/[abl]{4}/
但這也可以匹配帶有2 a或2 b的單詞。
我覺得我需要對未來保持負面看法。 就像是:
[l|(ab)(?!\1)]{4}
這里的嘗試是我想要一個以l或a或b開頭而不是a或b開頭的單詞。
首先需要錨定模式以描述字符串的開始和結束位置:
對於整個字符串(字符串的^
開頭, $
結尾) :
^[abl]{4}$
或要查找較大文本中的單詞,請使用單詞邊界( [A-Za-z0-9_]
的字符與其他字符之間的限制) :
\b[abl]{4}\b
然后,您需要說l
必須出現兩次(或者a
和b
只能出現一次,但是更復雜):
對於整個字符串:
^(?=.*l.*l)[abl]{4}$
較大的文字:
\b(?=\w*l\w*l)[abl]{4}\b
為了避免兩個a或b,可以使用另一個前瞻:
對於整個字符串:
^(?=.*l.*l)(?=l*al*b|l*bl*a)[abl]{4}$
較大的文字:
\b(?=\w*l\w*l)(?=l*al*b|l*bl*a)[abl]{4}\b
關於[l|(ab)(?!\\1)]
:在字符類中,特殊的正則表達式字符或字符序列失去其特殊含義,所有字符均視為文字。 因此, [l|(ab)(?!\\1)]
與[)(!|?1abl]
相同(由於\\1
是字符類中的未知轉義序列,因此反斜杠將被忽略。)
請注意,在幾個約束條件下,模式會很快變得難看。 您應該考慮另一種方法,該方法包括用\\b[abl]{4}\\b
捕獲所有單詞並再次對其進行過濾(例如,使用count_chars
)。
$str ='abll labl ball aabl lblabla 1234';
$dict = 'abll';
$count = count_chars($dict);
$result = [];
if (preg_match_all('~\b[abl]{4}\b~', $str, $matches)) {
$result = array_filter($matches[0], function ($i) use ($count) {
return $count == count_chars($i);
});
}
print_r($result);
如果要動態指定字母,然后生成將完成所有工作的regexp-這將是一項非常昂貴的工作。
簡單方法:您可以生成簡單的正則表達式,例如/^[abl]{4}$/
,從字典中獲取與他匹配的所有單詞,然后分別驗證每個單詞-檢查字母數量。
更有效的方法:您可以使用以下字母排序列表在字典中為單詞建立索引:
word: apple | index: aelpp
word: pale | index: aelp
等等。 要從字母列表中獲取所有單詞,您只需對這些字母進行排序並找到具有“ index”值的完全匹配項。
編輯:所以對於47個字母,它將是
\\b(?:((?(1)(?!))l1)|((?(2)(?!))l2)|...|((?(47)(?!))l47)){47}\\b
字母可以是重復的,例如4 a和15 r(但不能再重復),等等...
( 不受排列的影響 )
要僅匹配一次故障訂單項,
使用條件允許每個項目匹配一次,
但沒有更多。
它並不復雜,並且不受排列的影響。
每次都能工作!
\\b(?:((?(1)(?!))a)|((?(2)(?!))b)|((?(3)(?!))l)|((?(4)(?!))l)){4}\\b
擴展
\b
(?:
( # (1)
(?(1)(?!))
a
)
|
( # (2)
(?(2)(?!))
b
)
|
( # (3)
(?(3)(?!))
l
)
|
( # (4)
(?(4)(?!))
l
)
){4}
\b
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.