如何匹配与Perl中的特定模式不匹配的字符串?

时间:2010-01-21 11:51:11

标签: regex perl

我知道除了使用正则表达式的给定字符之外,很容易匹配任何内容。

$text = "ab ac ad";
$text =~ s/[^c]*//g; # Match anything, except c.

$text is now "c".

我不知道如何“除”字符串而不是字符。我怎么能“匹配任何东西,除了'ac'”?尝试[^(ac)]和[^“ac”]但没有成功。

有可能吗?

6 个答案:

答案 0 :(得分:5)

以下解决了巴特K所述的第二种意义所理解的问题。评论:

>> $text='ab ac ad';
>> $text =~ s/(ac)|./\1/g;
>> print $text;
ac

此外,'abacadac' - > 'acac'

应该注意的是,在大多数实际应用中,负面前瞻证明比这种方法更有用。

答案 1 :(得分:2)

如果你只想检查字符串是否不包含“ac”,只需使用否定。

$text = "ab ac ad";

print "ac not found" if $text !~ /ac/;

print "ac not found" unless $text =~ /ac/;

答案 2 :(得分:2)

$text =~ s/[^c]*//g; // Match anything, except c.

<强> @ssn 下, 关于你的问题的一些评论:

  1. “//”不是Perl中的评论。只要 “#”是。
  2. “[^ c] *” - 没有必要 那里的“*”。 “[^ c]”表示 由所有人组成的人物类 字母“c”以外的字符。 然后使用/ g修饰符, 意味着文本中的所有这些事件都将是 替换(在您的示例中,使用 没有)。 “零或更多”(“*”) 因此修饰语是多余的。
  3.   

    我怎么能“匹配任何东西,除了   'ac'“?试过[^(ac)]和[^”ac“]   没有成功。

    请阅读有关字符类的文档(请参阅命令行中的“perldoc perlre”或http://perldoc.perl.org/perlre.html在线) - 您会看到它指出方括号内的字符列表RE将“匹配列表中的任何字符”。含义顺序不相关,没有“字符串”,只有字符列表。 “()”和双引号在方括号内也没有特殊含义。

    现在我不确定你为什么要谈论匹配,然后给出一个替代的例子。但是要查看字符串是否与子字符串“ac”不匹配,您只需要取消匹配:

    use strict; use warnings;
    my $text = "ab ac ad";
    if ($text !~ m/ac/) {
       print "Yey the text doesn't match 'ac'!\n"; # this shouldn't be printed
    }
    

    假设您有一个文本字符串,其中嵌入了多次出现的子字符串。如果您只想要围绕子字符串的文本,只需删除所有出现的子字符串:

    $text =~ s/ac//g;
    

    如果你想反过来 - 除了所有出现的子字符串之外的所有文字都删除了,我会建议像:

    use strict; use warnings;
    my $text = "ab ac ad ac ae";
    my $sub_str = "ac";
    my @captured = $text =~ m/($sub_str)/g;
    my $num = scalar @captured;
    print (($sub_str x $num) . "\n");
    

    这基本上计算子字符串在文本中出现的次数,并使用“x”运算符打印子字符串的次数。不是很优雅,我相信Perl-guru可以提供更好的东西。


    <强> @ennuikiller

    my $text = "ab ac ad";
    $text !~ s/(ac)//g; # Match anything, except ac.
    

    这是不正确的,因为它会在“使用警告”下生成一个警告(在无效上下文中使用否定模式绑定(!〜))并且除了从文本中删除所有子串“ac”之外什么都不做,这可以更简单地写成我在上面写的:

    $text =~ s/ac//g;
    

答案 3 :(得分:2)

更新:在对您的问题发表评论时,您提到要清除维基标记并删除{{ ... }}的平衡序列。 Perl FAQ的第6部分涵盖了这一点:Can I use Perl regular expressions to match balanced text?

考虑以下计划:

#! /usr/bin/perl

use warnings;
use strict;

use Text::Balanced qw/ extract_tagged /;

# for demo only
*ARGV = *DATA;

while (<>) {
  if (s/^(.+?)(?=\{\{)//) {
    print $1;
    my(undef,$after) = extract_tagged $_, "{{" => "}}";

    if (defined $after) {
      $_ = $after;
      redo;
    }
  }

  print;
}

__DATA__
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. {{delete me}} Sed quis
nulla ut dolor {{me too}} fringilla
mollis {{ quis {{ ac }} erat.

其输出:

Lorem ipsum dolor sit amet, consectetur
adipiscing elit.  Sed quis
nulla ut dolor  fringilla
mollis {{ quis  erat.

对于您的特定示例,您可以使用

$text =~ s/[^ac]|a(?!c)|(?<!a)c//g;

也就是说,只有当ac不属于ac序列时,才会删除它。

一般来说,这对于正则表达式来说很棘手。

假设您不希望foo后跟可选空格,然后bar $str。通常,单独检查更清晰,更容易。例如:

die "invalid string ($str)"
  if $str =~ /^.*foo\s*bar/;

你可能也对an answer to a similar question感兴趣,我在那里写了

my $nofoo = qr/
  (      [^f] |
    f  (?! o) |
    fo (?! o  \s* bar)
  )*
/x;

my $pattern = qr/^ $nofoo bar /x;

要了解并发症,请阅读Mark Dominus的How Regexes Work。引擎将正则表达式编译为状态机。当匹配时,它将输入字符串提供给状态机并检查状态机是否处于接受状态。因此,要排除字符串,您必须指定一台接受除特定序列之外的所有输入的计算机。

可能有帮助的是/v正则表达式开关,它像往常一样创建状态机,但随后补充所有状态的接受状态位。与单独的检查相比,这很难说这是否真的有用,因为/v正则表达式可能会以不同的方式让人感到惊讶。

如果您对理论细节感兴趣,请参阅Peter Linz的An Introduction to Formal Languages and Automata

答案 4 :(得分:1)

你可以使用index()

$text = "ab ac ad";
print "ac not found" if ( index($text,"ac") == -1 );

答案 5 :(得分:0)

您可以轻松修改此正则表达式。

use Test::More 0.88;

#Match any whole text that does not contain a string
my $re=qr/^(?:(?!ac).)*$/;
my $str='ab ac ad';

ok(!$str=~$re);

$str='ab af ad';
ok($str=~$re);

done_testing();