使用正则表达式在HTML文本中查找带双字母的单词

时间:2014-06-21 10:47:41

标签: regex perl tags

如何编写正则表达式,查找文档中包含双字母的所有单词?

我用双重字母表示:“正在进行”,“d和s在地址”,“o在工具中”等等。我想在HTML文档的<body>部分中匹配这些单词吗?

下面是一些显示我要做的事情的代码:

while (<>){
    if (/<body(.*)>/ .. /<\/body>/){
        foreach ($_){
        print $_ =~ /\b\w{0,10}(\w)\1\w{0,10}\b/;
        }
    }   
}

3 个答案:

答案 0 :(得分:2)

这不是一个明显的任务,首先是因为使用正则表达式解析html是危险的。有了所有关于这样做的免责声明,这里有一份关于这项工作的正则表达式:

(?s)(?:<body>|\G)(?:.(?!</body>))*?\K\b\w*(\w)\1\w*\b

请参阅the demo

Perl:

@result = $subject =~ m%(?s)(?:<body>|\G)(?:.(?!</body>))*?\K\b\w*(\w)\1\w*\b%g;
  • (?s)允许点匹配换行符
  • (?:<body>|\G)匹配<body>或上一场比赛的结束位置
  • (?:.(?!</body>))*?懒惰地匹配未跟随结束</body>标记的字符
  • \K告诉引擎放弃到目前为止匹配的内容与返回的匹配
  • \b\w*(\w)\1\w*\b匹配由一些可选字符\b组成的单词(没有\w*边界),然后一个捕获的字符(\w)紧随其后,由捕获的第1组引用\1以及更多可选字符\w*

如果您只想允许字母(没有数字和下划线),请将所有\w替换为[a-z],并将(?s)替换为(?is),以使其不区分大小写

答案 1 :(得分:1)

以下是使用HTML::TreeBuilder::XPath的示例解决方案。它在<body>元素中找到HTML中的所有文本节点,将它们分成“单词”(使用您对\w+的定义)并打印包含重复字符的那些节点。

请注意,文本节点包含<script>标记内的JavaScript代码。

我希望你能看到使用真正的HTML解析器是多么容易。如果您对XPath不满意,可以使用其他几个。但是请不要挣扎于正则表达式来创建难以编写并且可能随时中断的内容

use strict;
use warnings;
use 5.010;

use HTML::TreeBuilder::XPath;

my $tree = HTML::TreeBuilder::XPath->new_from_url('http://www.perl.org/');

my @body_text = $tree->findvalues('/html/body//text()');

for my $word (map /\w+/g, @body_text) {
  say $word if $word =~ /(.)\1/;
}

<强>输出

Programming
www
Community
000
programming
free
books
000
community
Community
community
300
support
discussion
000
offer
opportunities
programming
discussion
collaboration
Hook
Zilla
Zilla
33
Zilla
Moos
BitTorrent
300
Current
Community
Need
look
Toolkit
need
www
2002
_setAccount
50555
https
https
ssl
http
www
google
setAttribute
appendChild
googleTranslateElementInit
google
50555
google_translate_element

答案 2 :(得分:0)

使用Mojo::DOM解析HTML。

以下内容可以轻松完成您的意思,而无需获取标记属性中的其他值或类似内容:

use strict;
use warnings;

use Mojo::DOM;

my $dom = Mojo::DOM->new(do {local $/; <DATA>});

for my $body ($dom->find('body')->each) {
    my $text = $body->all_text();
    for my $word ($text =~ m{\w+}g) {
        print "$word\n" if $word =~ /(.)\1/;
    }
}

__DATA__
<html>
<head>
<title>Dooble, but not me</title>
</head>
<body>
<h1>I'm a heeder</h1>
<p style="color: reed">I have more woods to find in heer.  How many wrrds can I misspell?  Plentee without even trying</p>
</body>
</html>

输出:

heeder
woods
heer
wrrds
misspell
Plentee

对于Mojo::DOM有用的8分钟介绍,请查看Mojocast Episode 5