【问题标题】:perl: strip html tags, manipulate text, and then return html tags to their original positionsperl:剥离 html 标签,操作文本,然后将 html 标签返回到它们的原始位置
【发布时间】:2013-06-25 14:40:26
【问题描述】:

我正在使用 Html::Strip 模块从文件中删除所有 html 标记。然后我想操作生成的文本(去除 html),最后将 html 标签返回到它们的原始位置。

我正在做的文本操作需要使用 split(/ /, $text) 将文本分成数组。然后我对生成的数组进行一些自然语言处理(包括将 new html 标记添加到一些关键词)。处理完文本后,我想将原始标签放回原处,同时保持我在此期间完成的文本操作不变。

如果我可以简单地从原始标签中删除所有空白,我会很满意(因为浏览器会忽略标签中的空白)。这样,我的 NLProcessing 可以简单地忽略作为标签的单词(包含“”)。

我尝试深入研究 Html::Strip 的内容(以根据我的需要对其进行修改),但我无法理解以下代码的作用:

  my $stripped = $self->strip_html( $text );
  if( $self->decode_entities && $_html_entities_p ) {
    $stripped = HTML::Entities::decode($stripped);
  }

好像 strip_html 是一个 sub,但我在任何地方都找不到那个 sub。

无论如何,感谢您的任何建议。


……第二天……

在与@amon 反复讨论之后,我想出了一个我认为足以满足我的目的的解决方案。 amon 把我推向了正确的方向,尽管他建议我不要做我已经做过的事情,哈哈。

这是一种野蛮的方法,但可以令人满意地完成工作。将其留在这里,以防其他人有与我相同的愿望并且不介意快速而肮脏的解决方案:

my $input = text.html;
my $stripped = $hs->parse($input);
$hs->eof;

所以现在我有两个字符串变量。一个是我要操作的html文件,另一个是同一个去掉html的文件。

my @marks = split(/\s/, $stripped);
@marks = uniq(@marks);

现在我有一个列表,列出了我的文件中出现的所有与 HTML 标记无关的单词。

$input = HTML::Entities::decode($input);
$input =~ s/\</ \</g; 
$input =~ s/\>/\> /g; 
$input =~ s/\n/ \n /g; 
$input =~ s/\r/ \r /g; 
$input =~ s/\t/ \t /g;

现在我已经解码了包含 var 的 HTML,并确保没有单词与“”或非空格空白字符相匹配。

foreach my $mark(@marks) { $input =~ s/ \Q$mark\E / TAQ\+$mark\TAQ /g; }
$input =~ s/TAQ\+TAQ//g;

现在我用“+”“标记”了每个单词,并使用 TAQ 分隔符将单词与非单词分开。我现在可以在 TAQ 上拆分并在执行 NLP 和文本操作时忽略任何不包含“+”的项目。完成后,我重新加入并删除所有“+”。然后用一些巧妙的编码,删除我插入的所有额外空格,BAM!我现在已经完成了我的 NLProcessing,已经处理了文本,并且我的所有 HTML 仍然在正确的位置.

这里有很多警告,我不打算一一详述。最大的问题是需要先解码然后编码,再加上 HTML::Strip 并不总是剥离所有 javascript 或无效 HTML 的事实。有一些方法可以解决这个问题,但我再次没有空间或时间在这里讨论这个问题。

感谢 amon 的帮助,我欢迎任何批评或建议。我是新手。

【问题讨论】:

    标签: html perl nlp strip


    【解决方案1】:

    模块HTML::Strip 使用XS 胶水语言将Perl 代码与C 代码连接起来。您可以找到XS file,例如在(元)cpan 上。它包括一个实现实际算法的文件strip_html.c。由于 XS 文件中的定义,strip_html 子在 Perl 代码中作为HTML::Strip 包的一部分可用。因此,它可以作为适当对象的方法调用。

    那段代码的解释

    my $stripped = $self->strip_html( $text );
    

    这将对$text 的内容调用C 函数以去除所有HTML 标记。然后将剥离的数据分配给$stripped

    if( $self->decode_entities && $_html_entities_p ) {
      $stripped = HTML::Entities::decode($stripped);
    }
    

    使用-p 为变量名添加后缀是lispish tradition 以指示布尔变量(或谓词,在数学中)。在这里,它指示是否可以加载HTML::Entitiesmy $_html_entities_p = eval 'require HTML::Entities';。如果配置选项decode_entities 设置为真值,并且可以加载HTML::Entities,则将在剥离数据中解码实体。

    示例:给定输入

    <code> $x &lt; $y </code>
    

    然后剥离会产生

    $x &lt; $y
    

    解码实体就可以了

    $x < $y
    

    【讨论】:

    • 太棒了。谢谢你的解释。非常彻底。不幸的是,strip_html.c 有点超出我的想象,而且似乎不是我可以操纵或模仿的东西。所以我仍然坚持我原来的问题:剥离 html,操作文本,返回 html。在这方面有什么建议吗?
    • @Nick 你想要做的很可能是一个非常困难的问题。我可能会以这样一种方式编写我的 NLP 代码:它适用于预标记化的输入,并且会通过空白标记。然后,标签信息可以保存为空白标记,例如&lt;p style="..."&gt; foo &amp;amp; bar&lt;/p&gt; 可以设为 [p =&gt; {style =&gt; "..."}], " ", "foo", " ", "&amp;", " ", "bar", [undef, "p"],其中数组引用和空白被视为空白。当您的处理添加的标记跨越半个标签时,这会崩溃,例如&lt;p&gt; foo &amp; &lt;mark&gt;bar&lt;/p&gt; baz&lt;/mark&gt;,无效。
    • 当然,可以通过将输出清理为&lt;p&gt; foo &amp; &lt;mark&gt;bar&lt;/mark&gt;&lt;/p&gt;&lt;mark&gt; baz&lt;/mark&gt; 之类的内容来缓解这种情况。这并不太复杂,应该可以通过一个简单的下推自动机来实现。但这可能会产生您不想要的输出。此外,使用特殊的无操作令牌可能不适用于外部库。玩得开心,弄清楚如何正确地做这些事情!
    • 标记化是个好主意。有没有一种方便的方法来标记所有不在 html 标签的 内的单词?我能想到的最好的是$text="&lt;p&gt; foo &amp; &lt;mark&gt;bar&lt;/p&gt; baz&lt;/mark&gt;"; $stripped=$hs-&gt;parse($text); @array1=split(/ /, $text);@array2=split(/ /, $stripped); for my $a(@array1){ for my $b(@array2) { $a=join('',$a,\^) if $a=~/$b/;}} 现在@array1 将所有非 html 单词标记为 '^' 符号,我的 NLProcessing 可以忽略非标记单词,完成后我可以删除标记。你能想出更好的方法吗?
    • 当然,我必须确保标签与文本单词之间用空格隔开。
    猜你喜欢
    • 2013-07-11
    • 1970-01-01
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    相关资源
    最近更新 更多