[英]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.