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


Select two consecutive words by regular expression

既然,我是正则表达式的新手;我想创建一个正则表达式来选择两个连续的单词。

例如,当我给出这个短语:"Hello people # regulareexpression sucks!"

它必须返回这两个单词:

人中国话

(# RegularExpression

——# RegularExpression糟透了!

我尝试了这个/'w's'w/i,但它没有工作:(

$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中,但是没有理由不添加它,并且在现实世界中,额外的空白确实有一种潜入文本的方式。(但一定要加上+,而不是*;必须至少有一个空白字符。)

(?=...)是一个积极的展望。您可以使用它们来检查是否有可能在当前匹配位置匹配所包含的子表达式,而不需要推进到匹配位置。然后,通常,您继续匹配不同的子表达式,而不是在前瞻性中。

这里有一个棘手的地方:尽管与forward子表达式匹配的字符不被使用,但是子表达式中的任何捕获组都照常工作。我的正则表达式(?=('S+'s+'S+))中的forward匹配并捕获下一个两个单词序列。然后(假设forward成功)'S+'s+以正常方式匹配,为下一次尝试设置正确的匹配位置。

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

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

总之,听起来你真正的想要做的只是在空格上分割字符串,然后你可以自己收集所有的单词对。您可以使用类似preg_split('/'s+/', $str)的代码进行分割,以返回由所有空格分隔的单词组成的数组,然后您可以在数组上任意迭代。

我很确定这是可能的用正则表达式做,但这里的pickle是正则表达式消耗观察它们匹配,所以"返回"获得重叠匹配是一件棘手的事情。Regex不是适合这个的工具;锤子不能吸,因为它不能(正确地)处理螺丝。

如果我是你,我就这么做:

$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!

就像其他人说的那样,这在标准的pcre正则表达式中似乎是不可能的(编辑:哎呀,这是错误的,参见图灵的答案),你最好选择另一种策略。

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

见文档中的"BACKTRACKING CONTROL"部分pcre.org/pcre.txt

这个模式应该可以工作:

/[^'s]+'s[^'s]+/i

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