我有一个4个字母的字典。我想写一个正则表达式来翻阅字典并匹配给出一组字母的所有单词。
假设我传入a,b,l,l
。我想找到那些完全符合这些字母的所有单词。
我知道我可以/[abl]{4}/
,但这也会匹配2 a或2 b的单词。
我觉得我需要做一个消极的展望。类似的东西:
[l|(ab)(?!\1)]{4}
这里的尝试是我想要一个以l或a或b开头并且后面没有a或b的单词。
答案 0 :(得分:2)
首先需要锚定模式来描述字符串的开始和结束位置:
表示整个字符串(^
字符串的开头,$
字符串的结尾):
^[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);
答案 1 :(得分:0)
如果你想动态指定字母然后生成将完成所有工作的正则表达式 - 这将是一项非常昂贵的工作。
简单的方法:您可以生成简单的正则表达式,如/^[abl]{4}$/
,从字典中获取与他匹配的所有单词,然后单独验证每个单词 - 检查字母数量。
更有效的方法:您可以使用排序的字母列表在字典中索引您的单词,如下所示:
word: apple | index: aelpp
word: pale | index: aelp
等等。要从字母列表中获取所有单词,您只需对这些字母进行排序,并找到与“索引”值完全匹配。
答案 2 :(得分:0)
编辑:因此,对于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