Perl 在 HTML/XML 标签内的单词周围添加 <a></a>
Perl add <a></a> around words within an HTML/XML tag
我有一个格式如下的文件:
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">
</>
There could be one or several words within the <p class="ul1">
tag.
这在 Perl
单行中可能吗?
提前致谢。感谢任何帮助。
One-liner:
cat text | perl -pE 's{<p class="ul1">\K.*?(?=<\/p>)}{ join ", ", map {qq|<a href="entry://$_">$_</a>|} split /, */, $& }eg'
使用模块解析文件并迭代所需的元素(<p>
of class ul1
)。从每个短语中提取 comma-separated 个短语,并将 link 包裹在它们周围;然后用新内容替换元素。最后把变化的树写出来
使用HTML::TreeBuilder (with its workhorse HTML::Element)
use warnings;
use strict;
use feature 'say';
use HTML::Entities;
use HTML::TreeBuilder;
my $file = shift // die "Usage: [=10=] 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 很重要,请使用 HTML::Tidy or HTML::PrettyPrinter.
之类的工具通过
在one-liner?呐,太多了。并且请不要使用正则表达式,因为在路上会遇到麻烦;它需要密切的工作才能做到正确,很容易出现错误,对最小的细节很敏感,并且对输入的最细微变化也很脆弱。那时它 可以 完成这项工作。有图书馆的原因。
这项工作的另一个好工具是 Mojo::DOM。例如
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(只是更好,并且注意不需要处理实体)。
较新的模块版本提供了 new_tag 方法,可以将上面的附加 link 制作为
my $new = join ', ',
map { $e->new_tag('a', 'href' => "entry://$_", $_) } @w;
什么处理了一些微妙的需求(HTML 转义了一个)。添加此方法时,主要文档 不要说 ,请参阅 changelog(2018 年 5 月,所以应该在 v5.28 中;它适用于我的 5.29.2)。
我将显示的示例填充到此文件以进行测试:
<!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 文档的片段,而是一个文件(如所述)如图所示,作为使用 HTML 的自定义格式;除了所需的更改外,其余部分需要保留。
一个特别不愉快的细节被证明是</>
部分; HTML::TreeBuilder
、Mojo::DOM
和 XML::LibXML
† 中的每一个在解析时都将其丢弃。我找不到让他们保留那块的方法。
是Marpa::HTML按要求处理了整个片段,改变了要求的内容,而保留了其余部分。
use warnings;
use strict;
use feature 'say';
use Path::Tiny;
use Marpa::HTML qw(html);
my $file = shift // die "Usage: [=14=] 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;
classul1
的<p>
标签的处理和之前一样:用逗号分割内容,每片包裹成一个<a>
标签,然后用 ,
加入他们
这会打印(添加 line-breaks 和缩进以提高可读性)
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
is an extremely liberal HTML parser. Marpa::HTML
does not reject any documents, no mater how poorly they fit the HTML standards.
这里它处理了一段自定义的 HTML-like 标记,留下 </>
之类的东西。
†
请参阅 以获取使用 XML::LibXML
非常宽松地处理 HTML 的示例
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;
'
我有一个格式如下的文件:
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">
</>
There could be one or several words within the
<p class="ul1">
tag.
这在 Perl
单行中可能吗?
提前致谢。感谢任何帮助。
One-liner:
cat text | perl -pE 's{<p class="ul1">\K.*?(?=<\/p>)}{ join ", ", map {qq|<a href="entry://$_">$_</a>|} split /, */, $& }eg'
使用模块解析文件并迭代所需的元素(<p>
of class ul1
)。从每个短语中提取 comma-separated 个短语,并将 link 包裹在它们周围;然后用新内容替换元素。最后把变化的树写出来
使用HTML::TreeBuilder (with its workhorse HTML::Element)
use warnings;
use strict;
use feature 'say';
use HTML::Entities;
use HTML::TreeBuilder;
my $file = shift // die "Usage: [=10=] 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 很重要,请使用 HTML::Tidy or HTML::PrettyPrinter.
在one-liner?呐,太多了。并且请不要使用正则表达式,因为在路上会遇到麻烦;它需要密切的工作才能做到正确,很容易出现错误,对最小的细节很敏感,并且对输入的最细微变化也很脆弱。那时它 可以 完成这项工作。有图书馆的原因。
这项工作的另一个好工具是 Mojo::DOM。例如
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(只是更好,并且注意不需要处理实体)。
较新的模块版本提供了 new_tag 方法,可以将上面的附加 link 制作为
my $new = join ', ',
map { $e->new_tag('a', 'href' => "entry://$_", $_) } @w;
什么处理了一些微妙的需求(HTML 转义了一个)。添加此方法时,主要文档 不要说 ,请参阅 changelog(2018 年 5 月,所以应该在 v5.28 中;它适用于我的 5.29.2)。
我将显示的示例填充到此文件以进行测试:
<!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 文档的片段,而是一个文件(如所述)如图所示,作为使用 HTML 的自定义格式;除了所需的更改外,其余部分需要保留。
一个特别不愉快的细节被证明是</>
部分; HTML::TreeBuilder
、Mojo::DOM
和 XML::LibXML
† 中的每一个在解析时都将其丢弃。我找不到让他们保留那块的方法。
是Marpa::HTML按要求处理了整个片段,改变了要求的内容,而保留了其余部分。
use warnings;
use strict;
use feature 'say';
use Path::Tiny;
use Marpa::HTML qw(html);
my $file = shift // die "Usage: [=14=] 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;
classul1
的<p>
标签的处理和之前一样:用逗号分割内容,每片包裹成一个<a>
标签,然后用 ,
这会打印(添加 line-breaks 和缩进以提高可读性)
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
is an extremely liberal HTML parser.Marpa::HTML
does not reject any documents, no mater how poorly they fit the HTML standards.
这里它处理了一段自定义的 HTML-like 标记,留下 </>
之类的东西。
†
请参阅 XML::LibXML
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;
'