需要帮助贪心量词

时间:2009-06-02 20:29:57

标签: regex perl greedy

我在Perl中进行简单的搜索和替换,但我需要一些帮助。这些是文件中的行:

1001(seperator could be "anything")john-1001(seperator could be "anything")mark
1001(seperator could be "anything")mark-1001(seperator could be "anything")john

我想为john分配一个新的userID,比如2001.所以这就是我想要的结果:

2001($1)john-1001-mark
1001-mark-2001($1)john

当john第一次出现时,我的正则表达式正常,但是当mark是第一次时,它就搞砸了。

4 个答案:

答案 0 :(得分:3)

几乎不可能在不知道分隔符是什么的情况下回答这个问题 - 哪些字符,多少个字符等等。非贪婪的任意分隔符看起来像这样:

s/\b1001\b(?=.*?\bjohn\b)/2001/

当匹配最小中间字符数时,这将替换“1001”后跟“john”。 .*?.*的非贪婪版本。但是,正则表达式总是匹配,所以这仍然匹配

1001-mark-1001-john

换句话说,这不仅仅是贪婪问题。我们需要至少定义以下三个方面之一:

  • 分隔符可以包含的字符。
  • 分隔符无法包含的字符。
  • 分隔符中的字符数。

如果我们假设分隔符不能包含“word”字符(a-z,0-9和下划线),我们可以得到一些可行的东西:

s/\b1001\b(?=\W+?\bjohn\b)/2001/

已知部分(“1001”和“john”)被限制以防止它们与这些子串匹配其他字符串。 (感谢Chas注意到边缘情况。)

答案 1 :(得分:3)

试试这个:

#!/usr/bin/perl

use strict;
use warnings;

while (<DATA>) {
    s/\b1001-john\b/2001-john/;
    print;
}

__DATA__
1001-john-1001-mark
1001-mark-1001-john
11001-john
1001-johnny

\b阻止其匹配"1001-john"以外的内容。有关详细信息,请参阅perldoc perlre的“断言”部分。


嗯,听起来你需要一个sexeger

#!/usr/bin/perl

use strict;
use warnings;

while (<DATA>) {
    my $s = reverse;
    $s =~ s/\bnhoj(.*?)1001\b/nhoj${1}1002/;
    $s = reverse $s;
    print $s;
}

__DATA__
1001-john-1001-mark
1001-mark-1001-john
11001-john
1001-johnny

性爱的基本思想是反转字符串,使用反向正则表达式,然后反转结果。问题是.*?为您提供了第一场比赛中最短的字符串,而不是最短的字符串。当然,由于"1001-mark-2001-john".*?匹配,"-mark-2001-"仍有问题。最好确定文件格式是什么并解析它而不是尝试使用正则表达式。

答案 2 :(得分:0)

我猜测你的评论中的分隔符并不总是一个连字符,实际上可能不止一个字符。

对于这种情况,请尝试:

s/\d+([^\d]*)john/2001$1john/

这将在更换过程中保持“1001”和“john”之间的分隔符不变。请注意,分隔符中不允许任何数字,因此即使在“标记”之后出现“john”(因为“-mark-1001-”不是有效的分隔符),这也会起作用。

答案 3 :(得分:-1)

它可能类似

$s = '1001-mark-1001-john';
$s =~ s/(\d+)(-john)/2001$2/i;
print $s;