用正则表达式选择两个连续的单词

时间:2011-08-30 23:01:30

标签: php regex

因为,我是正则表达式的新手;我想制作一个正则表达式来选择两个连续的单词。

例如,当我给出这句话时:“Hello people #RegularExpression很糟糕!”

必须回复这几个词:

- 你好人

-people #RegularExpression

- #RegularExpression糟透了!

我尝试了这个/\w\s\w/i,但它不起作用:(

5 个答案:

答案 0 :(得分:4)

$s = "Hello people #RegularExpression sucks!";
preg_match_all('~(?=(\S+\s+\S+))\S+\s+~', $s, $matches);
print_r($matches[1]);

输出:

Array
(
    [0] => Hello people
    [1] => people #RegularExpression
    [2] => #RegularExpression sucks!
)

说明:

\S+匹配一个或多个非空白字符。您的\w错误有两个原因:它只匹配一个字符;它只匹配一个所谓的字符(相当于[A-Za-z0-9_])。在此测试用例中没有必要将+添加到\s,但是没有理由来添加它,并且额外的空格确实有一种潜入文本的方式在现实世界。 (但请务必添加+,而不是*;其中必须至少有一个空白字符。)

(?=...)positive lookahead。您可以使用它们来检查它是否可能以匹配当前匹配位置的封闭子表达式,而不会提前匹配位置。然后,通常,您继续匹配不同的子表达式,而不是先行。

这是一个棘手的问题:虽然前瞻子表达式匹配的字符不是消耗的,但子表达式中的任何捕获组都照常工作。我的正则表达式中的前瞻,(?=(\S+\s+\S+))匹配并捕获下一个双字序列。然后(假设前瞻成功)\S+\s+以正常方式匹配,为下次尝试正确设置匹配位置。

此技术应适用于支持捕获组和前瞻的任何正则表达式。这包括PHP以及所有其他主要语言(Perl,JavaScript,.NET,Python,Java ......)。从每个匹配中仅访问第一个捕获组内容的技术因语言的不同而异,但PHP使$matches[1]变得容易。

答案 1 :(得分:2)

您的正则表达式实际上会匹配由空格分隔的两个字母。因此,根据您的输入,您将获得o pn s。执行此操作的另一个问题是对字符串执行全局正则表达式搜索会返回非重叠实例。因此,正确的正则表达式可以返回Hello people#RegularExpression sucks!,但它不会返回people #RegularExpression,因为它与Hello people重叠。第三个问题是你如何定义单词?经典定义和\w原子使用的定义是字母数字或下划线。因此,#RegularExpression不匹配,因为#不是单词字符。

总而言之,这听起来像你 想要做的只是在空格上分割你的字符串,然后你可以自己收集所有的单词对。您可以使用preg_split('/\s+/', $str)之类的内容进行拆分,以返回所有以空格分隔的单词的数组,然后您可以根据需要迭代数组。

答案 2 :(得分:1)

我很确定可能与正则表达式有关,但这里的pickle是正则表达式消耗它们匹配的手表,因此“返回”以获得重叠匹配是一件棘手的事情。正则表达式不是正确的工具;锤子不会吮吸,因为它不能(正确地)处理螺钉。

如果我是你,我就会这样做:

$str =  "Hello people #RegularExpression does not suck!";
$arr = explode(' ', $str);

for ($i=0; $i<count($arr) - 1; $i++) {
    echo implode(' ', array_slice($arr, $i, 2)) . "\n";
}

输出:

Hello people
people #RegularExpression
#RegularExpression does
does not
not suck!

答案 3 :(得分:0)

像其他人所说的那样,在标准的pcre正则表达式中,这似乎是不可能的(编辑:糟糕,这是错误的,请参阅Alan的回答),你最好选择另一种策略。

让我补充说,它似乎存在一个实验性和棘手的解决方案:回溯动词。

请参阅文档pcre.org/pcre.txt

中的“回溯控制”部分

答案 4 :(得分:-1)

这种模式应该有效:

/[^\s]+\s[^\s]+/i

匹配每个非空格,后跟一个空白字符和其他非空格字符。