Php 尝试使用preg_match_all将4个或更多字符的单词与3个或更少字符的单词分组

Php 尝试使用preg_match_all将4个或更多字符的单词与3个或更少字符的单词分组,php,regex,Php,Regex,我正在尝试使用PHP中的preg\u match\u all()将4个或更多字符的单词与3个或更少字符的单词分组。我这样做是为了一个关键字搜索功能,用户可以输入像“大象”这样的东西,我不能让任何结果返回到只有“一”在他们 因此,我需要将三个或更少字符的关键字与下一个或上一个关键字放在一起,而不是用空格分隔关键字(例如“An”、“大象”)。(如“大象”、“历史”) 为了实现这一点,我尝试使用条件子模式,但我不确定我是否真的在正确的轨道上 以下是迄今为止我得到的最好的: (\s\S{1,3}\s*)

我正在尝试使用PHP中的
preg\u match\u all()
将4个或更多字符的单词与3个或更少字符的单词分组。我这样做是为了一个关键字搜索功能,用户可以输入像“大象”这样的东西,我不能让任何结果返回到只有“一”在他们

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

为了实现这一点,我尝试使用条件子模式,但我不确定我是否真的在正确的轨道上

以下是迄今为止我得到的最好的:

(\s\S{1,3}\s*)?(?(1)\S+)
然而,我似乎也在匹配一大堆空白。 有人能给我指一下正确的方向吗

在“大象的历史”的例子中,我试图让它创建两个匹配:“大象的历史”和“大象”


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

您试图做的事情有些复杂,它会导致歧义。是大象的历史
[大象的历史]
还是
[大象的历史]
?排除一组特定的停止词或符合某些条件的词可能更好

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

$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
// )

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

\b(?:[\w'-]{1,3}\W+[\w'-]{4,}|[\w'-]{4,}\W+[\w'-]{1,3}|[\w'-]{4,})\b
  • \b
    开始,它将
  • [\w'-]{1,3}\w+[\w'-]{4,}
    匹配1-3个单词字符,后跟一个或多个非单词字符,后跟
    [\w'-]{4,}\b
    4个或多个单词字符
  • |[\w'-]{4,}\w+[\w'-]{1,3}
    或先匹配4+个单词,然后匹配较短的单词
  • |[\w'-]{4,}
    或匹配任何至少有4个字符的单词。(必要时减少)
)

如果输入的内容是“我看过微积分A,你在微积分B?”
,也可以看到问题;输出:
I visted
calculation A
在calculation
中,因为前面的单词具有优先级


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

输出至:


(链接即将到期)

关于“大象的历史”应该怎么办?理想情况下,两个匹配的“大象的历史”和“大象”使用
preg\u split
我开始认为这可能是一个更好的解决方案,通常像
a
an
of
by
as
,删除位于
的,以提高搜索功能的性能和准确性。如果需要查找,可以使用几个索引进行搜索。@Jonny5真正的用例是搜索像“微积分a”这样的课程,在这种情况下,“a”非常重要。谢谢你的回答,但我尽量保留3个或更少字符的单词。我只需要将它们合并到周围的4个或更多字符的单词中。“大象的历史”可以用任何一种方式分割。我只需要以某种方式对它们进行分组,以防止搜索函数搜索“of”的所有实例。但是我不能在这个特定的用例中省略“of”,因为它是有价值的。真正的用例是搜索课程名称,如“微积分A”,Jonny非常感谢。事实上,我自己刚刚找到了一个解决办法
/((\b\w{1,3}\s)+\w{4,})|(\w{4,}(\s\w{1,3}\b))|(\w{4,})/i
是我使用的正则表达式,它与您的非常相似。就您的编辑而言,“我访问了演算A,您在演算b中?”这在当前的应用程序中是非常正确的,因为搜索非常零碎。e、 《美国科学史》将输出《美国科学史》、《美国科学史》,再次感谢您的坚持!我觉得这很有趣,不客气@ChrisB。此外,你的模式似乎做得很好。我不确定这是否适用于大型文本或短语:)
$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
)