我有一个这样的文件格式:
Eye color
<p class="ul">Eye color, color</p> <p class="ul1">blue, cornflower blue, steely blue</p> <p class="ul1">velvet brown</p> <link rel="stylesheet" href="a.css">
</>
weasel
<p class="ul">weasel</p> <p class="ul1">musteline</p> <link rel="stylesheet" href="a.css">
</>
<p class="ul1">
中用,
分隔的每个单词都应包裹在<a>
标记中,如下所示:
Eye color
<p class="ul">Eye color, color</p> <p class="ul1"><a href="entry://blue">blue</a>, <a href="entry://cornflower blue">cornflower blue</a>, <a href="entry://steely blue">steely blue</a></p> <p class="ul1"><a href="entry://velvet brown">velvet brown</a></p> <link rel="stylesheet" href="a.css">
</>
weasel
<p class="ul">weasel</p> <p class="ul1"><a href="entry://musteline">musteline</a></p> <link rel="stylesheet" href="a.css">
</>
<p class="ul1">
标记内可能有一个或几个单词。
{@ {1}}单行有可能吗?
先谢谢了。任何帮助表示赞赏。
答案 0 :(得分:5)
使用模块解析文件并遍历所需的元素(类<p>
的{{1}})。从每个中提取那些用逗号分隔的短语,并在它们周围包装链接;然后用新内容替换元素。最后将更改后的树写出来。
使用HTML::TreeBuilder(及其主力HTML::Element)
ul1
在您的情况下,元素(use warnings;
use strict;
use feature 'say';
use HTML::Entities;
use HTML::TreeBuilder;
my $file = shift // die "Usage: $0 file\n";
my $tree = HTML::TreeBuilder->new_from_file($file);
foreach my $elem ($tree->look_down(_tag => "p", class => "ul1")) {
my @new_content;
for ($elem->content_list) {
my @w = split /\s*,\s*/;
my $wrapped = join ", ",
map { qq(<a href="entry://$_">).$_.q(</a>) } @w;
push @new_content, $wrapped;
}
$elem->delete_content;
$elem->push_content( @new_content );
};
say decode_entities $tree->as_HTML;
)将在$elem
中具有一项,因此您不必将修改后的内容收集到数组(content_list
)中,但可以对其进行处理仅一件,简化了代码。使用上面的列表当然不会受到伤害。
我将该程序的输出重定向到@new_content
文件。生成的文件在换行符上很节俭。如果漂亮的HTML很重要,请使用HTML::Tidy或HTML::PrettyPrinter之类的工具进行传递。
单线吗?不,太多了。并且请不要使用正则表达式,因为这会给您带来麻烦。它需要紧密的工作才能正确完成,容易陷入越野车,对最小的细节敏感,并且即使输入的更改很小,也很脆弱。这就是它可以进行的工作。有图书馆的原因。
Mojo::DOM是完成这项工作的另一个好工具。例如
.html
产生与上述相同的HTML(效果更好,请注意无需处理实体)。
较新的模块版本提供了new_tag
方法,通过该方法可以在上面创建其他链接
use Mojo::DOM;
use Path::Tiny; # only to read the file into a string easily
my $html = path($file)->slurp;
my $dom = Mojo::DOM->new($html);
foreach my $elem ($dom->find('p.ul1')->each) {
my @w = split /,/, $elem->text;
my $new = join ', ',
map { qq(<a href="entry://$_">).$_.q(</a>) } @w;
$elem->replace( $new );
}
say $dom;
可以满足一些微妙的需求(HTML转义为一个)。添加此方法时的主要文档不要说,请参见changelog(2018年5月,据称在v5.28中;适用于我的5.29.2)。
我将显示的示例填充到此文件中进行测试:
my $new = join ', ',
map { $e->new_tag('a', 'href' => "entry://$_", $_) } @w;
更新 已明确的是,给定的标记片段不仅是大概完整的HTML文档的一部分,而且还是一个自定义格式的文件(如上所述)使用HTML;除了必需的更改之外,其余所有都需要保留。
一个特别令人不快的细节被证明是<!DOCTYPE html> <title>Eye color</title> <body>
<p class="ul">Eye color, color</p>
<p class="ul1">blue, cornflower blue, steely blue</p>
<p class="ul1">velvet brown</p> <link rel="stylesheet" href="a.css"></>
weasel
<p class="ul">weasel</p>
<p class="ul1">musteline</p> <link rel="stylesheet" href="a.css"></>
</body> </html>
的一部分; </>
,HTML::TreeBuilder
和Mojo::DOM
†中的每一个在解析时都将其丢弃。我找不到让他们坚持下去的方法。
Marpa::HTML根据需要处理了整个片段,更改了要询问的内容,而其余部分则保留下来。
XML::LibXML
类use warnings;
use strict;
use feature 'say';
use Path::Tiny;
use Marpa::HTML qw(html);
my $file = shift // die "Usage: $0 file\n";
my $html = path($file)->slurp;
my $marpa = Marpa::HTML::html(
\$html,
{
'p.ul1' => sub {
return join ', ',
map { qq(<a href="entry://$_">).$_.q(</a>) }
split /\s*,\s*/, Marpa::HTML::contents();
},
}
);
say $$marpa;
的{{1}}标记的处理与上面相同:以逗号分割内容并将每段内容包装到<p>
标记中,然后使用{ {1}}
此打印(添加了换行符和缩进以提高可读性)
ul1
此模块的整体方法适用于此类任务
<a>
是一个非常宽松的HTML解析器。,
不会拒绝任何文档,也不会满足HTML标准的要求。
此处处理了自定义的类似HTML的标记,将Eye color
<p class="ul">Eye color, color</p>
<a href="entry://blue">blue</a>,
<a href="entry://cornflower blue">cornflower blue</a>,
<a href="entry://steely blue">steely blue</a>
<a href="entry://velvet brown">velvet brown</a>
<link rel="stylesheet" href="a.css">
</>
weasel
<p class="ul">weasel</p> <a href="entry://musteline">musteline</a>
<link rel="stylesheet" href="a.css">
</>
之类的内容保留在原处。
†
有关使用Marpa::HTML
答案 1 :(得分:1)
perl -0777 -MWeb::Query=wq -lne'
my $w = wq $_; my $sep = ", ";
$w->filter("p.ul1")->each(sub {
my (undef, $e) = @_;
$e->html(join $sep, map {
qq(<a href="entry://$_">$_</a>)
} split $sep, $e->text);
});
print $w->as_html;
'
答案 2 :(得分:0)
单线:
cat text | perl -pE 's{<p class="ul1">\K.*?(?=<\/p>)}{ join ", ", map {qq|<a href="entry://$_">$_</a>|} split /, */, $& }eg'