正则表达式匹配某些单词但不匹配其他单词

时间:2015-11-18 13:58:16

标签: regex perl

我正在使用perl中的正则表达式,我正在尝试创建一个正则表达式,找到两个单词,其中一个以d结尾,下一个单词以p开头(但不是ph)。这是我的正则表达式,有效:

d\s(p[^h])}

但是,我也想这样排除“和”这个词(但只在这个模式中),所以我试图使用负向前瞻,所以我的代码看起来像这样:

if ($text =~ m{d\s(p[^h])} && $text =~ m{(?:(?!\sand\s))}) {
        print "Yes\n";
        } else {
                }

然而,这似乎不起作用。

以下是一些示例输入/输出:

sand pet - >是

沙子电话 - >无

去和宠物 - >无

沙宠和 - >是

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

您可以使用单个正则表达式完成所需的操作:

/(?<!\ban)d\s(p[^h]\w+)/

其中:

  • \b是单词边界锚点,不会消耗任何字符,但会确保排除的字词为and而不是sand。它匹配\w(字词字符:[a-zA-Z0-9_])和\W(不在字词字符中)和^和{{1}的相同位置}。
  • $ (?<!\ban)d前面没有隔离 d,从技术上讲,几乎等同于an

在线Demo

如果您不需要单独提取第一个和第二个单词,您也可以删除捕获组并添加一些容差(单词之间的一个或多个空格):

(?<!\Wan)

注意:此正则表达式实际上是搜索由{{1}中的一个或多个空格分隔的if ( $input =~ m/(?<!\ban)d\s+p(?!h)/ ) print "Yes\n"; else print "No\n"; (前面没有非子字符串d) }后面没有an。它没有大声说出单词。如果你想确保有多个字符的单词,你可以添加一个前导和尾随p

另一个Demo

答案 1 :(得分:0)

你变得太复杂了。该负向前瞻应用于字符串,并与任何子字符串匹配。所以它将匹配任何不包含\sand\s子串,它总是起作用,因为零长度子串是'ok'。

您可以在启用调试时看到这一点:

#!/usr/bin/env perl
use strict;
use warnings;
use re 'debug';

while ( <DATA> ) {
    print if m{(?:(?!\sand\s))};
}

__DATA__
sand pet 
sand phone 
go and pet 
sand pet and
empty

前瞻与另一种模式一起用来说'匹配这个,但前提是这是(或不是)下一个'。

类似于:

m{d\s(p[^h])} and not m{\sand\s};

可以做你想做的事 - 或者,只需将其分解为几个阶段:

#!/usr/bin/env perl
use strict;
use warnings;

#use re 'debug';

while (<DATA>) {
    my ($capture) = m{d\s(p[^h])};
    if ( $capture and not $capture =~ m/\sand\s/ ) {
        print $capture, " => ", $_, "\n";
    }
}

__DATA__
sand pet 
sand phone 
go and pet 
sand pet and
empty

答案 2 :(得分:0)

尝试将所有内容都放在一个正则表达式中通常是不合适的。该程序有一个子程序ok_words,它检查一对单词以查看您的标准是否适用。调用代码获取字符串中的每对单词,如果任何一对的测试结果为true,则打印yes,否则no

这些是您的测试,以及检查它们的Perl代码

  • 第一个以d - /\d\z/

  • 结尾
  • ...但不是and - “ne”和“

  • 第二个以p开头,但不是ph - /\Ap(?!h)/

这是应用它们的程序

use strict;
use warnings 'all';

use List::MoreUtils qw/ any /;

while ( <DATA> ) {
    chomp;

    my @w = split;

    if ( any { ok_words( $w[$_], $w[$_+1] ) } 0 .. $#w-1 ) {
        print "$_ -> yes\n";
    }
    else {
        print "$_ -> no\n";
    }

}

sub ok_words {
    my ($this, $next) = map lc, @_;

    $this =~ /d\z/ and $this ne 'and' and $next =~ /\Ap(?!h)/;
}

__DATA__
sand pet
sand phone
go and pet
sand pet and

输出

sand pet -> yes
sand phone -> no
go and pet -> no
sand pet and -> yes