我需要找到并替换html字符串中的xml标签,这不是完整的xml,这就是为什么我不能使用xml解析器来处理它。所以我需要手动找到xml标签并用这些html字符串中的内容替换它们。
包含xml标记的html字符串示例:
some text<p>hello p</p>
<vars type="text" name="fname" age="64" style="<b>color='red'</b>
Class::SubClass->color" /> other text or html open tags like <p><table><tr>
所以我需要找到xml&#34; vars&#34;带有可变数量的可选属性的标签,并用内容替换它们。
答案 0 :(得分:2)
不要使用正则表达式来解析HTML。而是使用像Mojo::DOM
这样的实际HTML解析器。有一个关于在mojocast episode 5
使用此模块的8分钟视频。
以下内容将使用您的html,并将您的特殊变量标记转换为一些新文本。
use strict;
use warnings;
use Mojo::DOM;
# Parse
my $dom = Mojo::DOM->new(do {local $/; <DATA>});
for my $var ($dom->find('vars')->each) {
my $type = $var->{type};
my $name = $var->{name};
$var->replace("<b>name is $name</b> + <i>type is $type</i>");
}
print $dom;
__DATA__
<html>
<head>
<title>Always use a parser, not a regex</title>
</head>
<body>
some text<p>hello p</p>
<vars type="text" name="fname" age="64" style="<b>color='red'</b>
Class::SubClass->color" /> other text or html open tags like <p><table><tr><td></td></tr></table>
</body></html>
输出:
<html>
<head>
<title>Always use a parser, not a regex</title>
</head>
<body>
some text<p>hello p</p>
<b>name is fname</b> + <i>type is text</i> other text or html open tags like <p></p><table><tr><td></td></tr></table>
</body></html>
答案 1 :(得分:0)
看看一些Perl解析器的XML和HTML,如Moler :: DOM,如上面的Miller回答并查看XML :: TreePP,我发现他们正在使用正则表达式来解析整个内容,所以我尝试了他们的正则表达式和得到好结果可能需要一些优化。
这是我做的:
my $text =<<'XHTML';
some text
<p>hello p</p>
<vars type="text" name= "fname" single='single quoted' unqouted=noquotes hastags=" <b>color='red'</b> Class::SubClass->color"/>
other text or html open tags like
<vars type="text" name= "lname" single1='single quoted' unqouted1=noquotes hastags1=" <b>bgcolor='red'</b> Class::SubClass->bgcolor">
<table><tr>
<vars name="mname" />
XHTML
while ( $text =~ m{(<vars\s+([^\!\?\s<>](?:"[^"]*"|'[^']*'|[^"'<>\/])*)/?>)}sxgi ) {
my $match = $1;
my $args = $2;
#print "[[$match]] \n{{$args}}\n\n";
#parse name=value attributes, values may be double or single quoted or unquoted
while ( $args =~ m/([^<>=\s\/]+|\/)(?:\s*=\s*(?:"([^"]*?)"|'([^']*?)'|([^>\s\/]*)))?\s*/sxgi ) {
my $name = $1;
#any better solution with regex above to just get $2
my $value = $2? $2: ($3? $3 : $4);
print "$name=$value\n";
}
print "\n";
}
,这是预期的输出:
type=text
name=fname
single=single quoted
unqouted=noquotes
hastags= <b>color='red'</b> Class::SubClass->color
type=text
name=lname
single1=single quoted
unqouted1=noquotes
hastags1= <b>bgcolor='red'</b> Class::SubClass->bgcolor
name=mname
当然代码中的变量$ match具有完整匹配,因此我可以将其替换为我的内容。
匹配属性的第二个正则表达式需要优化,我不满意这一行:
my $value = $2? $2: ($3? $3 : $4);
可以修改正则表达式以获取$ 2中的属性值。
Mojo :: Dom中使用的正则表达式是
my $ATTR_RE = qr/
([^<>=\s\/]+|\/) # Key
(?:
\s*=\s*
(?:
"([^"]*?)" # Quotation marks
|
'([^']*?)' # Apostrophes
|
([^>\s\/]*) # Unquoted
)
)?
\s*
/x;
my $END_RE = qr!^\s*/\s*(.+)!;
my $TOKEN_RE = qr/
([^<]+)? # Text
(?:
<\?(.*?)\?> # Processing Instruction
|
<!--(.*?)--\s*> # Comment
|
<!\[CDATA\[(.*?)\]\]> # CDATA
|
<!DOCTYPE(
\s+\w+
(?:(?:\s+\w+)?(?:\s+(?:"[^"]*"|'[^']*'))+)? # External ID
(?:\s+\[.+?\])? # Int Subset
\s*
)>
|
<(
\s*
[^<>\s]+ # Tag
\s*
(?:$ATTR_RE)* # Attributes
)>
|
(<) # Runaway "<"
)??
/xis;
如果关闭标签有或没有斜线&gt;我只是搞砸了它以匹配或/&gt;。