尝试使用preg_match_all将包含3个或更少字符的单词组成4个或更多字符的单词

时间:2015-02-07 20:25:38

标签: php regex

我正在尝试使用PHP中的preg_match_all()将包含3个或更少字符的单词组成4个或更多字符的单词。我这样做是为了一个关键字搜索功能,用户可以输入像“大象”这样的东西,而且我不能得到任何只有“An”的结果。

因此,我不需要用空格分隔关键字(例如“An”,“elephant”),而是需要将三个或更少字符的关键字与下一个或上一个关键字放在一起。 (例如“大象”,“历史”)

为了实现这一点,我试图使用条件子模式,但我不确定我是否真的在这里正确。

这是迄今为止我所获得的最好成绩:

(\s\S{1,3}\s*)?(?(1)\S+)

然而,我似乎也匹配了一大堆空白空间。 有人可以指出我正确的方向吗?

在“大象历史”的情况下,我试图让它创造两个匹配:“历史”和“大象”。

我不能简单地省略“停止词”,因为它们在这种情况下很重要。现实生活中的用例是搜索“微积分A”等课程标题,在这种情况下,“A”很重要。

2 个答案:

答案 0 :(得分:3)

看看这是否符合您的需求:

\b(?:[\w'-]{1,3}\W+[\w'-]{4,}|[\w'-]{4,}\W+[\w'-]{1,3}|[\w'-]{4,})\b
  • \b word boundaries开始......
  • [\w'-]{1,3}\W+[\w'-]{4,}匹配1-3个字符,后跟\W+个一个或多个非字字符,后跟[\w'-]{4,}\b个4个或更多字符。
  • |[\w'-]{4,}\W+[\w'-]{1,3}或首先匹配4个以上的单词,然后是较短的单词。
  • |[\w'-]{4,}或匹配任何至少包含4个字符的字词。 (如果需要,减少)

Test at regex101.com; Regex FAQ

如果输入是"I visted Calculus A, you in Calculus B?",也可以看到问题;输出:I vistedCalculus Ain Calculus,因为前面的单词具有优先权。


一个PHP示例($out[0]将保存匹配项)

$str = "
An elephant in the garden 
history of elephants
Algebra A B-movies";

$pattern = '~\b(?:
[\w\'-]{1,3}\W+[\w\'-]{4,}|
[\w\'-]{4,}\W+[\w\'-]{1,3}|
[\w\'-]{4,}
)\b~x';

if(preg_match_all($pattern, $str, $out)) {
  print_r($out[0]);
}

输出到

Array
(
    [0] => An elephant
    [1] => the garden
    [2] => history of
    [3] => elephants
    [4] => Algebra A
    [5] => B-movies
)

Test at eval.in链接即将过期

答案 1 :(得分:1)

您尝试做的事情有一些并发症,这会引起歧义。是History of elephants [History of] [elephants]还是[History] [of elephants]?您可能最好只排除一组特定的停用词或符合某些条件的字词。

如果要排除3个或更少字符的单词,可以尝试以下操作。 你说你已经在空格处拆分了关键字,所以你应该有一个单词数组。您可以根据字长({3个字符)array_filter该数组,并且您应该拥有要使用的字词列表。

$words = array('no', 'na', 'sure', 'definitely');

function length_filter($word) {
    return mb_strlen($word) > 3;
};

$longer_than_3 = array_filter($words, 'length_filter');
print_r($longer_than_3);

// Array
// (
//     [2] => sure
//     [3] => definitely
// )