php正则表达式负向前瞻

时间:2016-04-05 20:59:38

标签: php regex

我有一个4个字母的字典。我想写一个正则表达式来翻阅字典并匹配给出一组字母的所有单词。

假设我传入a,b,l,l。我想找到那些完全符合这些字母的所有单词。

我知道我可以/[abl]{4}/,但这也会匹配2 a或2 b的单词。

我觉得我需要做一个消极的展望。类似的东西:

[l|(ab)(?!\1)]{4} 

这里的尝试是我想要一个以l或a或b开头并且后面没有a或b的单词。

3 个答案:

答案 0 :(得分:2)

首先需要锚定模式来描述字符串的开始和结束位置:

表示整个字符串^字符串的开头,$字符串的结尾)

^[abl]{4}$

或要在较大的文字中查找字词,请使用字词边界[A-Za-z0-9_]中的字符与其他字符之间的限制)

\b[abl]{4}\b

然后你需要说l必须发生两次(或ab必须只出现一次,但它更复杂):

表示整个字符串:

^(?=.*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