Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在HTML中匹配';这不是内部标签吗?_Html_Regex_Perl - Fatal编程技术网

如何在HTML中匹配';这不是内部标签吗?

如何在HTML中匹配';这不是内部标签吗?,html,regex,perl,Html,Regex,Perl,给定如下字符串: <a href="http://blah.com/foo/blah">This is the foo link</a> 。。。还有一个像“foo”这样的搜索字符串,我想突出显示HTML文本中出现的所有“foo”——但不是在标记中。换句话说,我想得到这个: <a href="http://blah.com/foo/blah">This is the <b>foo</b> link</a> 但是,简

给定如下字符串:

<a href="http://blah.com/foo/blah">This is the foo link</a>

。。。还有一个像“foo”这样的搜索字符串,我想突出显示HTML文本中出现的所有“foo”——但不是在标记中。换句话说,我想得到这个:

<a href="http://blah.com/foo/blah">This is the <b>foo</b> link</a>

但是,简单的搜索和替换将不起作用,因为它将匹配标记的href中的部分URL

那么,以一个问题的形式来表达上述内容:如何限制正则表达式,使其只匹配HTML标记之外的文本

注意:我保证所讨论的HTML永远不会像:

<img title="Haha! Here are some angle brackets to screw you up: ><" />

Edit:是的,我当然知道CPAN中有复杂的库,甚至可以解析最恶劣的HTML,从而减少对此类正则表达式的需要。在很多情况下,我都会这么做。但是,这不是其中之一,因为保持此脚本简短、无外部依赖关系非常重要。我只想要一行正则表达式

编辑2:同样,我知道Template::Refine::Fragment可以为我解析所有HTML。如果我在写一个应用程序,我肯定会使用这样的解决方案。但这不是一个应用程序。它只不过是一个shell脚本。这是一段一次性代码。在这种情况下,作为一个可以传递的独立文件是非常有价值的。“嘿,运行这个程序”比“嘿,安装一个Perl模块,然后运行这个——等等,什么,你以前从未使用过CPAN?好的,运行Perl-MCPAN-eshell(最好以root用户身份运行)然后它会问你一大堆问题,但你真的不需要回答。不,不要害怕,这不会破坏任何东西。听着,你不需要仔细回答每个问题——只需反复按enter键。不,我保证,这不会破坏任何东西。”

现在,将上述内容乘以大量用户,他们想知道为什么他们一直使用的简单脚本不再那么简单,而现在所做的只是将搜索词改为粗体


因此,虽然Template::Refine::Fragment可能是其他人HTML解析问题的答案,但它不是这个问题的答案。我只需要一个正则表达式,它可以处理脚本实际需要解析的非常有限的HTML子集。

通常,您需要将HTML解析为DOM,然后遍历文本节点。我将使用Template::Refine实现以下目标:

#!/usr/bin/env perl

use strict;
use warnings;
use feature ':5.10';

use Template::Refine::Fragment;

my $frag = Template::Refine::Fragment->new_from_string('<p>Hello, world.  <a href="http://foo.com/">This is a test of foo finding.</a>  Here is another foo.');

say $frag->process(
    simple_replace {
        my $n = shift;
        my $text = $n->textContent;
        $text =~ s/foo/<foo>/g;
        return XML::LibXML::Text->new($text);
    } '//text()',
)->render;
#/usr/bin/env perl
严格使用;
使用警告;
使用特征“:5.10”;
使用Template::Refine::Fragment;
我的$frag=Template::Refine::Fragment->new_from_string(“你好,world。这里是另一个foo”);
说$frag->process(
简单替换{
我的$n=班次;
my$text=$n->textContent;
$text=~s/foo//g;
返回XML::LibXML::Text->new($Text);
}“//text()”,
)->渲染;
这将产生:

<p>Hello, world.  <a href="http://foo.com/">This is a test of &lt;foo&gt; finding.</a>  Here is another &lt;foo&gt;.</p> 
你好,世界。这是另一个foo。

无论如何,不要用正则表达式解析结构化数据。HTML不是“常规的”,它是“上下文无关的”


编辑:最后,如果您在程序中生成HTML,并且必须对字符串执行类似的转换,“您做错了”。您应该构建一个DOM,并且只在所有内容都已转换时对其进行序列化。(但是,您仍然可以通过
new\u from\u dom
构造函数使用TR。)

如果您可以绝对保证HTML中没有尖括号,而不是用于打开和关闭标记的尖括号,那么这应该可以:

s%(>|\G)([^<]*?)($key)%$1$2<b>$3</b>%g

s%(>|\G)([^以下正则表达式将匹配标记之间或标记外部的所有文本:

<.*?>(.*?)<.*?>|>(.*?)<
(.*?)|>(.*<
然后您可以根据需要对其进行操作。

试试这个


(?=>)?(\w[^>]+?)(?=要从嵌套标记中去除可变大小的内容,可以使用这个正则表达式,它实际上是一个小型正则语法。(注意:PCRE机器)


(?)。(使用正则表达式解析HTML非常困难。正如您的示例所示,这很难做到正确。)正则表达式在考虑注释和CDATA节时失败。(基于正则表达式的解析器很好,但您需要存储比正则表达式单独存储更多的状态。这就是为什么您使用解析器而不是随机正则表达式。)我自己生成HTML。它没有注释或CDATA部分。脚本是25行。我不会添加对外部文件的依赖性——你建议的是过度工程的定义。但是你看,我已经为你做了工程。重用……你听说过吗?是的……这就是为什么其他人说你实际上应该使用HTML解析器,而不是简单的正则表达式。我确实同意他们的观点,但是如果你真的想使用s///那么就把你自己弄出来;-)这些都是错误的。试着在“foooo blabla foo\n fooo”中突出显示“foo”重新发明轮子太有趣了!现在这很有趣,一个被接受的答案是-3票…我应该删除它:-(@Vlad:感谢测试用例--但是,我还是自己生成HTML。它只能有少量可能的表单中的一种,而那不是其中之一。不过,我已经更新了正则表达式来处理您的测试用例。
(?=>)
在其余部分匹配时不匹配。
(?)
是您想要的。(将
(?=>)?
替换为
(?)
(?)