替换不按我的预期工作

时间:2013-06-08 02:26:58

标签: regex perl

我正在尝试编写一个Perl脚本,它将改变一个看起来像这样的行......

<li><em>01 &#8211; Chapters 1-4</em> &#8211; 00:14:36 <br />

......让它看起来像这样......

01 &#8211; Chapters 1-4

......没什么大不了的?我只是在我的Perl脚本中执行\(.*\)这样的事情:

#!/usr/bin/perl -w
use strict;

while(<DATA>) {
        my $line = $_;
        chomp($line);
        if ( $line =~ /^<li>/ ) {
                $line =~ s/<em>\(.*\)<\/em>/$1/g;
                print "[" . $line . "]\n";
        }
}
__DATA__
<li><em>01 &#8211; Chapters 1-4</em> &#8211; 00:14:36 <br />
<li><em>02 &#8211; Chapters 5-8</em> &#8211; 00:10:52 <br />
<li><em>03 &#8211; Chapters 9-14</em> &#8211; 00:19:16 <br />
<li><em>04 &#8211; Chapters 15-18</em> &#8211; 00:13:30 <br />
<li><em>05 &#8211; Chapters 19-22</em> &#8211; 00:17:01 <br />
<li><em>06 &#8211; Chapters 23-25</em> &#8211; 00:16:44 <br />
<li><em>07 &#8211; Chapter 26</em> &#8211; 00:10:35 <br />
red@ubuntu:~/scripts$ ./test.pl

当我运行脚本时,我得到了这个输出......

[<li><em>01 &#8211; Chapters 1-4</em> &#8211; 00:14:36 <br />]
[<li><em>02 &#8211; Chapters 5-8</em> &#8211; 00:10:52 <br />]
[<li><em>03 &#8211; Chapters 9-14</em> &#8211; 00:19:16 <br />]
[<li><em>04 &#8211; Chapters 15-18</em> &#8211; 00:13:30 <br />]
[<li><em>05 &#8211; Chapters 19-22</em> &#8211; 00:17:01 <br />]
[<li><em>06 &#8211; Chapters 23-25</em> &#8211; 00:16:44 <br />]
[<li><em>07 &#8211; Chapter 26</em> &#8211; 00:10:35 <br />]

......我在这里做错了什么?

由于

更新:

感谢您的所有回复。他们非常有帮助。 我已将代码更改为此...

red@ubuntu:~/scripts$ cat test.pl
#!/usr/bin/perl -w
use strict;

while(<DATA>) {
        my $line = $_;
        chomp($line);
        if ( $line =~ /^<li>/ ) {
                $line =~ s/<em>(.*)<\/em>/$1/g;
                print "[" . $line . "]\n";
        }
}
__DATA__
<li><em>01 &#8211; Chapters 1-4</em> &#8211; 00:14:36 <br />
<li><em>02 &#8211; Chapters 5-8</em> &#8211; 00:10:52 <br />
<li><em>03 &#8211; Chapters 9-14</em> &#8211; 00:19:16 <br />
<li><em>04 &#8211; Chapters 15-18</em> &#8211; 00:13:30 <br />
<li><em>05 &#8211; Chapters 19-22</em> &#8211; 00:17:01 <br />
<li><em>06 &#8211; Chapters 23-25</em> &#8211; 00:16:44 <br />
<li><em>07 &#8211; Chapter 26</em> &#8211; 00:10:35 <br />

...但仍然没有达到输出我希望我得到这个......

red@ubuntu:~/scripts$ ./test.pl
[<li>01 &#8211; Chapters 1-4 &#8211; 00:14:36 <br />]
[<li>02 &#8211; Chapters 5-8 &#8211; 00:10:52 <br />]
[<li>03 &#8211; Chapters 9-14 &#8211; 00:19:16 <br />]
[<li>04 &#8211; Chapters 15-18 &#8211; 00:13:30 <br />]
[<li>05 &#8211; Chapters 19-22 &#8211; 00:17:01 <br />]
[<li>06 &#8211; Chapters 23-25 &#8211; 00:16:44 <br />]
[<li>07 &#8211; Chapter 26 &#8211; 00:10:35 <br />]

...看起来已移除<em></em>,但我只想要<em></em>之间的文字。

5 个答案:

答案 0 :(得分:6)

您只替换更新版本中匹配的部分行。

print "[$1]\n" if /<em>(.*)<\/em>/;

只会为您提供(.*)捕获组捕获的内容。然后你不必费心去替换。

但请注意安迪莱斯特在评论中的谨慎态度。这很好用,或者你的测试数据很好,但是HTML因打破你的正则表达而臭名昭着,特别是如果你说了一句神奇的短语“但我真正的HTML数据总是完全采用这种形式”。

答案 1 :(得分:3)

您正在使用与\(.*\)(匹配的)。使用(.*)提取匹配项。

http://ideone.com/UTFDZo

根据您的更新...您需要使用以下

$line =~ s/<em>(.*)<\/em>(.*)/$1/g;

http://ideone.com/AkJtIo

我强烈建议您考虑合并@ AndyLester的评论。

答案 2 :(得分:2)

如果你想捕捉,你想要

 (...)

Escaped parens试图匹配parens。

答案 3 :(得分:2)

您所做的就是从字符串的第一部分周围删除<em>标记。如果你想删除其他所有内容,请写下

use strict;
use warnings;

while(<DATA>) {
  print "[$1]\n" if /^<li><em>([^<>]+)/;
}

__DATA__
<li><em>01 &#8211; Chapters 1-4</em> &#8211; 00:14:36 <br />
<li><em>02 &#8211; Chapters 5-8</em> &#8211; 00:10:52 <br />
<li><em>03 &#8211; Chapters 9-14</em> &#8211; 00:19:16 <br />
<li><em>04 &#8211; Chapters 15-18</em> &#8211; 00:13:30 <br />
<li><em>05 &#8211; Chapters 19-22</em> &#8211; 00:17:01 <br />
<li><em>06 &#8211; Chapters 23-25</em> &#8211; 00:16:44 <br />
<li><em>07 &#8211; Chapter 26</em> &#8211; 00:10:35 <br />

<强>输出

[01 &#8211; Chapters 1-4]
[02 &#8211; Chapters 5-8]
[03 &#8211; Chapters 9-14]
[04 &#8211; Chapters 15-18]
[05 &#8211; Chapters 19-22]
[06 &#8211; Chapters 23-25]
[07 &#8211; Chapter 26]

答案 4 :(得分:1)

您的第一次和第二次尝试包括以下内容:

$line =~ s/<em>\(.*\)<\/em>/$1/g;    # First version
$line =~ s/<em>(.*)<\/em>/$1/g;      # Second version

两个版本都没有对行的右端进行任何更改。命令s/f/r/表示搜索匹配f的内容并用r替换该部分,隐式命令意味着对字符串的其余部分不执行任何操作。

将命令编写为

$line =~ s/<em>(.*)<\/em>.*/$1/g;

说要找到(在em>之后)任意数量的字符,但不包括行尾或换行符。因此命令将删除其他想要的字符。

s///命令可以使用其他字符作为分隔符,这样可以更轻松地搜索包含/的字符串。所以上面的内容可能会更清楚地写成

$line =~ s!<em>(.*)</em>.*!$1!g;

在您给出的示例中,无需修改字符串。所描述的任务是在<em></em>对中打印文本并丢弃该行的其余部分。所以msw的答案中的代码可以满足所有需要。如果你正在处理大量性能很重要的文本,那么msw的方法可能更合适。