1

我正在尝试编写一个 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>and</em>被删除了,但我只想要<em>and之间的文本</em>

4

5 回答 5

6

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

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

只会给你(.*)捕获组捕获的内容。然后你就不必费心替换了。

但请注意安迪莱斯特在评论中的谨慎。这对您的测试数据来说效果很好,但是 HTML 因破坏您的正则表达式而臭名昭著,尤其是当您说出“但我真正的 HTML 数据将始终采用这种形式”的神奇短语时。

于 2013-06-08T02:51:16.550 回答
3

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

http://ideone.com/UTFDZo

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

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

http://ideone.com/AkJtIo

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

于 2013-06-08T02:51:37.677 回答
2

如果你想捕捉,你想要

 (...)

转义的括号尝试匹配括号。

于 2013-06-08T02:35:09.813 回答
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]
于 2013-06-08T12:44:46.567 回答
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 的方法可能更可取。

于 2013-06-08T11:22:06.110 回答