0

我正在 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 分配一个新的用户 ID,比如 2001。所以这就是我想要的结果:

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

当 john 是第一个时,我的正则表达式工作正常,但是当 mark 是第一个时,它就搞砸了。

4

4 回答 4

3

如果不知道分隔符可以是什么——哪些字符、多少个字符等,几乎不可能回答这个问题。非贪婪的任意分隔符如下所示:

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

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

1001-mark-1001-john

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

  • 分隔符可以包含的字符。
  • 分隔符不能包含的字符。
  • 分隔符中的字符数。

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

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

已知部分(“1001”和“john”)是有界的,以防止它们将其他字符串与这些子字符串匹配。(感谢 Chas 注意到这种极端情况。)

于 2009-06-02T20:41:38.470 回答
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

sexeger 的基本思想是反转字符串,使用反转的正则表达式,然后反转结果。问题在于,它.*?为您提供了第一次匹配的最短字符串,而不是最短的可能字符串。当然这仍然会有问题"1001-mark-2001-john"as the .*?will match "-mark-2001-"。确定文件格式并对其进行解析可能比尝试使用正则表达式更好。

于 2009-06-02T20:43:12.900 回答
0

我从您的评论中猜测分隔符并不总是连字符,实际上可以是多个字符。

对于这种情况,请尝试:

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

这将在替换过程中保持“1001”和“john”之间的分隔符完好无损。请注意,分隔符中不允许有数字,因此即使在“mark”之后出现“john”也可以使用(因为“-mark-1001-”不是有效的分隔符)。

于 2009-06-02T20:47:52.607 回答
-1

它可能是这样的

$s = '1001-mark-1001-john';
$s =~ s/(\d+)(-john)/2001$2/i;
print $s;
于 2009-06-02T20:44:19.183 回答