如何在Perl正则表达式中匹配最后一个字符之后的所有内容?

22
例如,返回字符串 axxxghdfx445 中最后一个 x 后面的部分(应该返回 445)。
7个回答

25
my($substr) = $string =~ /.*x(.*)/;

根据perldoc perlre:

默认情况下,定量子模式是"贪婪"的,也就是说,在允许模式其余部分匹配的情况下,它将尽可能多地匹配(在特定的起始位置)。

这就是为什么.*x会匹配到最后一个x出现的原因。


1
我建议采用 reko_t的答案避免使用贪婪的 .* - Stack Underflow
为什么?实际上会慢得多。在这种特殊情况下,永远不会发生回溯。Perl 要么使用 'x'(也称为浮动子串)的最后一次出现来确定组的起始位置,要么在没有 'x' 的情况下声明无匹配。 - Eugene Yarmash

17
最简单的方法是使用/([^x]*)$/

7
第一个答案已经很好了,但是当谈到“不包含某物”的时候... 我喜欢使用可以“匹配”它的正则表达式。
my ($substr) = $string =~ /.*x([^x]*)$/;

在某些情况下非常有用。


2
在正则表达式中,您不需要前导的“.*x”。 - runrig
没错,谢谢,但那只是为了说明“不包含x的某物”。 - benzebuth

6
最简单的方法不是使用正则表达式,而是使用简单的split()函数并获取最后一个元素。
$string="axxxghdfx445";
@s = split /x/ , $string;
print $s[-1];

1
创建一个临时数组真的值得吗?print (split /x/, $string)[-1];同样可以很好地工作。 - Zaid

4

我很惊讶没有人提到可以使用特殊变量来实现这一点,即$':"$'" 返回匹配字符串后面的所有内容。(perldoc perlre

my $str = 'axxxghdfx445';
$str =~ /x/;

# $' contains '445';
print $';

然而,这是有代价的(重点强调):
警告:一旦Perl看到您在程序中需要$&、"$'"或"$`"之一,它就必须为每个模式匹配提供它们。这可能会严重降低程序速度。Perl使用相同的机制来生成$1、$2等,因此每个包含捕获括号的模式都要付出代价。(要避免这种代价同时保留分组行为,请改用扩展正则表达式"(?: ... )"。)但是如果您从不使用$&、"$'"或"$`",则没有捕获括号的模式将不会受到惩罚。因此,如果可以的话,请避免使用$&、"$'"和"$`",但是如果您不能(某些算法确实需要它们),那么一旦您使用过它们,就可以随意使用它们,因为您已经付出了代价。从5.005版本开始,$&的代价不像其他两者那样高。
但是,等等,还有更多!你只需支付一个运算符的价格,现在就行动!
作为此问题的解决方法,Perl 5.10.0引入了"${^PREMATCH}"、"${^MATCH}"和"${^POSTMATCH}"三个变量,它们相当于"$`"、$&和"$'",但只有在使用"/p"(保留)修饰符执行成功匹配后才保证定义。与其标点符号字符等价物不同,使用这些变量不会产生全局性能损失,但代价是您必须告诉perl何时想要使用它们。
my $str = 'axxxghdfx445';
$str =~ /x/p;

# ${^POSTMATCH} contains '445';
print ${^POSTMATCH};

我谨卑微地建议,在大多数情况下,这种方法是最好和最直接的,因为它不需要您在模式构造中执行特殊操作以检索后匹配部分,并且没有性能损失。

1
除非你捕获的是“x”的第一次出现,而不是最后一次。 - runrig
@runrig:哈哈,你这是要毁了我的整个论文啊 :) 实际上,在这种情况下,/x([^x]*)$/ 更好... 我太过于沉迷于描述 $',而其他人都忽略了它。 - Ether
如果在“`”字符前面加上“\”,则可以避免引用中间的代码样式。 - CyberSkull

4

还有一种方法可以实现这个功能。虽然这不像用单个正则表达式那么简单,但如果你追求速度,这种方法很可能比使用正则表达式的任何方法都要快,包括split

my $s     = 'axxxghdfx445';
my $p     = rindex $s, 'x';
my $match = $p < 0 ? undef : substr($s, $p + 1);

2

正则表达式/([^x]+)$/ #假设 x 不是字符串的最后一个元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接