在给定的文本部分上搜索和替换脚本

时间:2011-07-28 18:52:35

标签: regex perl replace

我正在操作文本文件,并且需要构建一个perl脚本来运行搜索替换仅在给定文本部分的注释(本例中的章节),以便我可以转换此模式:

Chapter 1:1 text here(Note a) more text here(Note b)
2 text here(Note c) more text here(Note d)
3 text here(Note e) more text here(Note f)
4 text here(Note g) more text here(Note h)
Chapter 2:1 text here(Note i) more text here(Note j)
2 text here(Note k) more text here(Note l)
3 text here(Note m) more text here(Note n)
4 text here(Note o) more text here(Note p)
5 text here(Note q) more text here(Note r)
6 text here(Note s) more text here(Note t)

进入这个:

Chapter 1:1 text here(Note a) more text here(Note b)
2 text here(Note c) more text here(Note d)
3 text here(Note e) more text here(Note f)
4 text here(Note g) more text here(Note h)
Chapter 2:1 text here(Note a) more text here(Note b)
2 text here(Note c) more text here(Note d)
3 text here(Note e) more text here(Note f)
4 text here(Note g) more text here(Note h)
5 text here(Note i) more text here(Note j)
6 text here(Note k) more text here(Note l)

换句话说,我需要在每个新章的开头将每个音符的“计数器”设置为“a”。以下正则表达式匹配每一章:

(?s)^\w{1,10} \d{1,3}:\d{1,3}.+?\(Note \w\).+?(?=\w{1,10} \d{1,3}:\d{1,3})

我尝试使用像这样的while循环:

my @notes = ('Note a', 'Note b', 'Note c', 'Note d');
$Count = a;
foreach my $Marker (@notes) {
    $_=~s/(\\(Note\\))[a-z]/"$1".$Count++/e;
}

但我陷入困境,不可能想到一种方法来构建一个脚本,使其在每个章节中停止,然后再次开始直到结束。也许我使用了错误的方法?

如上所示(即第一个正则表达式),我需要做什么才能应用搜索并仅替换每个章节?

任何帮助将不胜感激。 谢谢!

编辑(7月30日)

两个答案都很好。我把第一个投票作为我的最爱,因为我更了解逻辑,但两者同样有效。

现在,作为我第一个问题的必然结果。如何在每行之前轻松地包含章节名称和章节编号顺序?像这样:

Chapter 1:1 text here(Note a) more text here(Note b)
Chapter 1:2 text here(Note c) more text here(Note d)
Chapter 1:3 text here(Note e) more text here(Note f)
Chapter 1:4 text here(Note g) more text here(Note h)
Chapter 2:1 text here(Note a) more text here(Note b)
Chapter 2:2 text here(Note c) more text here(Note d)
Chapter 2:3 text here(Note e) more text here(Note f)
Chapter 2:4 text here(Note g) more text here(Note h)
Chapter 2:5 text here(Note i) more text here(Note j)
Chapter 2:6 text here(Note k) more text here(Note l)

我是否需要使用变量并递增它或者是否有更简单的方法?

2 个答案:

答案 0 :(得分:3)

您应该将文本拆分为章节并单独处理。

# $book holds your text
my @chapters = split /^(?=Chapter\s+\d+:\d+)/m, $book;

for my $chap (@chapters) {
    my $cnt = 'a';
    $chap =~ s/(?<=\(Note )[a-z]/$cnt++/ge;
    print $chap;
}

这适用于您的示例。你只需要弄清楚如何处理超过26个音符(a-z)。

编辑:这是你可以逐行阅读文本并编写输出文件的方法:

open IN, 'infile.txt';
open OUT, '>', 'outfile.txt';

my $cnt;
for my $line (<IN>) {
    $cnt = 'a' if $line =~ /^Chapter\s+\d+:\d+/;
    $line =~ s/(?<=\(Note )[a-z]/$cnt++/ge;
    print OUT $line;
}

答案 1 :(得分:0)

你也可以不分裂,如下所示:

s/^(chapter\s+\d+:\d+)|(\(note\s+)[a-z]+(?=\))/$a='a'if$1; $1?$1:$2.$a++/gime;

PS:不要忘记use strict;use warnings;


基于OP评论的完整示例:

use strict;
use warnings;

open my $fh, '<', '/Users/rgp/Desktop/Test.txt' or die "cant open file: $!";
my $content = do { local $/ = undef; <$fh> };
close $fh;

$content =~ s/^(chapter\s+\d+:\d+)|(\(note\s+)[a-z]+(?=\))/$a='a'if$1; $1?$1:$2.$a++/gime;

print "Result:\n";
print $content;