无法使正则表达式工作

时间:2011-01-30 02:26:56

标签: html regex perl

我正在尝试使用正则表达式从文本文件中删除某些编码块。到目前为止,我的大多数正则表达式行都已删除代码。但是,我有两个问题:

1)每当我删除一段文本时,文本应该用空格代替,而不是简单地删除。 我的正则表达式代码的一个例子是:

$file =~ s/<ul(.*)>//gi;

使用基本格式<ul...>删除所有行,这是我想要它做的。但是,如前所述,它用空格替换标签和所有包含的数据,我想知道如何停止这种特殊的替换。

2)某些应该有效的正则表达式代码似乎没有。例如,我想删除

<script type="text/javascript"> 

function getCookies() { return ""; }

</script>

我尝试使用各种正则表达式代码,但似乎没有删除这些行。例如:

$file =~ s/<script type(.*)<\/script>//gi;

分别删除<script type...></script>标记,但保留

function getCookies() { return ""; }

...完好。我不确定为什么会发生这种情况,我非常想纠正这个问题。这怎么可能?对这两个问题中的任何一个问题的任何帮助都会非常有帮助!

编辑:对不起,我正在使用Perl! 另外:我刚尝试使用

$file =~ /<script type(.*)<\/script>/sgi

...以及/ msgi,但不幸的是都没有奏效。 <script type></script>标记都已删除,但出于某种原因

function getCookies() { return ""; } 

...部分留了下来。这是我的整个代码,包括所有正则表达式:

use strict;
use warnings;

my $firstarg;
if ($ARGV[0]){
  $firstarg = $ARGV[0];
}

open (DATA, $ARGV[1]);
my $file = do {local $/; <DATA>};

$file =~ s/<\!DOCTYPE(.*)>//gi;
$file =~ s/<html>//gi;
$file =~ s/<\/html>//gi;
$file =~ s/<title>//gi;
$file =~ s/<\/title>//gi;
$file =~ s/<head>//gi;
$file =~ s/<\/head>//gi;
$file =~ s/<link(.*)>//gi;
$file =~ s/<\link>//gi;
$file =~ s/CDM(.*)\;//gi;
$file =~ s/<\!(.*)->//gi;
$file =~ s/<body(.*)>//gi;
$file =~ s/<\/body>//gi;
$file =~ s/<div(.*)>//gi;
$file =~ s/<\/div>//gi;
$file =~ s/function(.*)>//gi;
$file =~ s/<noscript>//gi;
$file =~ s/<\/noscript>//gi;
$file =~ s/<a(.*)>//gi;
$file =~ s/<\/a>//gi;
$file =~ s/<ul(.*)>//gi;
$file =~ s/<\/ul>//gi;
$file =~ s/<li(.*)>//gi;
$file =~ s/<\/li>//gi;
$file =~ s/<form(.*)>//gi;
$file =~ s/<\/form>//gi;
$file =~ s/<iframe(.*)>//gi;
$file =~ s/<\/iframe>//gi;
$file =~ s/<select(.*)>//gi;
$file =~ s/<\/select>//gi;
$file =~ s/<textarea(.*)>//gi;
$file =~ s/<\/textarea>//gi;
$file =~ s/<b>//gi;
$file =~ s/<\/b>//gi;
$file =~ s/<H1>//gi;
$file =~ s/<H2>//gi;
$file =~ s/<H3>//gi;
$file =~ s/<H4>//gi;
$file =~ s/<H5>//gi;
$file =~ s/<H6>//gi;
$file =~ s/<\/H1>//gi;
$file =~ s/<\/H2>//gi;
$file =~ s/<\/H3>//gi;
$file =~ s/<\/H4>//gi;
$file =~ s/<\/H5>//gi;
$file =~ s/<\/H6>//gi;
$file =~ s/<option(.*)>//gi;
$file =~ s/<\/option>//gi;
$file =~ s/<p>//gi;
$file =~ s/<\/p>//gi;
$file =~ s/<span(.*)>//gi;
$file =~ s/<\/span>//gi;
$file =~ s/<!doctype(.*)>//gi;
$file =~ s/<base(.*)>//gi;
$file =~ s/<br>//gi;
$file =~ s/<hr>//gi;
$file =~ s/<img(.*)>//gi;
$file =~ s/<input(.*)>//gi;
$file =~ s/<link(.*)>//gi;
$file =~ s/<meta(.*)>//gi;
$file =~ s/<script type(.*)<\/script>//gi;
print $file;

好的,现在我删除了导致一个问题的<script>正则表达式,另一个已创建 - 使用:

$file =~ s/<script type(.*)<\/script>//gi;

删除<script ...>的第一个实例之间的所有内容,但不删除标记本身,而不是整个标记的重复。使用:

$file =~ s/<script type(.*)<\/script>//mgi;

导致完全相同的事情。使用:

$file =~ s/<script type(.*)<\/script>//sgi;

导致打印多个新行字符,但没有其他文本,/msgi相同。 呃,问题永远不会结束...... :(

新编辑:我想就发布使用正则表达式解析HTML的问题而道歉。我意识到编程界对这种做法存在相当大的反对(或者在实践中尝试,因为这似乎经常失败)。但是,我很遗憾地被迫使用正则表达式来解析选择的 HTML,这些HTML可以删除大多数(如果不是全部)HTML标记。我不被允许使用模块,尽管这是最明显和最简单的答案。

5 个答案:

答案 0 :(得分:1)

我不确定您使用的是哪种编程语言,但假设您使用的是perl,请尝试将s修饰符放在正则表达式的末尾:

$file =~ /<script type(.*)<\/script>/sgi

/s修饰符使.匹配任何字符,包括换行符(通常不包括换行符)


编辑:我道歉,我不擅长Perl,但我做了一些环顾四周,我终于意识到前面的s/是替换。在这种情况下,你的正则表达式应该是:

$file =~ s/<script type(.*)<\/script>/sgi

删除所有内容,包括脚本标记。但是,如果您只想要标记之间的内容:

$file =~ s/(<script type="[^"]*"\s*>).*(<\/script>)/$1$2/sgi;

注意斜杠之间的$1$2。此文本是替换文本。在这种情况下,我们使用捕获组的文本代替原始文本。在您的问题中,您连续使用两个斜杠(s/<ul(.*)>//gi),这意味着您将整个匹配替换为空字符串。在我看来,你实际上是想用s/<ul(.*)>/ /gi之类的空格(ASCII 20)替换所有内容。


自上次编辑以来 - 您需要为脚本使用一个正则表达式,因为您不需要内容:

$file =~ s/(<script type="[^"]*"\s*>).*(<\/script>)/ /sgi;

和所有其他标签的另一个通用正则表达式:

$file =~ s/<\/?\s*[^>]+>//sgi

我在这里假设您不希望仅限于上面显示的标签,您只想杀死所有HTML。有一个名为html2text的* nix实用程序可以执行此操作。您可能希望使用它。

答案 1 :(得分:1)

回复你的上一条评论:

perl -e'$file="<script etc>\nfoo\n</script>bar"; $file =~ s/<script.*script>//gis; print $file'

这似乎按照别人的建议做了你想做的事。但是,我不知道这与你正在尝试的有什么不同。

...

你可以加上这个:

use Data::Dumper;
$Data::Dumper::Useqq=1;
print Dumper($file);
在正则表达式之前

给我们结果?

.....

宾果:

$ file = ~list的第5行和第6行已将它们过滤掉:

$file =~ s/<\!DOCTYPE(.*)>//gi;
$file =~ s/<html>//gi;
$file =~ s/<\/html>//gi;
$file =~ s/<title>//gi;
$file =~ s/<\/title>//gi;
## Here they come:
$file =~ s/<script(.*)>//gi;
$file =~ s/<\/script>//gi;
$file =~ s/<head>//gi;

答案 2 :(得分:1)

如果您不允许使用除Perl正则表达式之外的任何内容,那么您可以调整the code to strip HTML tags from a text

#!/usr/bin/perl -w
use strict;
use warnings;

$_ = do { local $/; <DATA> };

# see http://www.perlmonks.org/?node_id=161281
# ALGORITHM:
#   find < ,
#       comment <!-- ... -->,
#       or comment <? ... ?> ,
#       or one of the start tags which require correspond
#           end tag plus all to end tag
#       or if \s or ="
#           then skip to next "
#           else [^>]
#   >
s{
  <               # open tag
  (?:             # open group (A)
    (!--) |       #   comment (1) or
    (\?) |        #   another comment (2) or
    (?i:          #   open group (B) for /i
      (           #     one of start tags
        SCRIPT |  #     for which
        APPLET |  #     must be skipped
        OBJECT |  #     all content
        STYLE     #     to correspond
      )           #     end tag (3)
    ) |           #   close group (B), or
    ([!/A-Za-z])  #   one of these chars, remember in (4)
  )               # close group (A)
  (?(4)           # if previous case is (4)
    (?:           #   open group (C)
      (?!         #     and next is not : (D)
        [\s=]     #       \s or "="
        ["`']     #       with open quotes
      )           #     close (D)
      [^>] |      #     and not close tag or
      [\s=]       #     \s or "=" with
      `[^`]*` |   #     something in quotes ` or
      [\s=]       #     \s or "=" with
      '[^']*' |   #     something in quotes ' or
      [\s=]       #     \s or "=" with
      "[^"]*"     #     something in quotes "
    )*            #   repeat (C) 0 or more times
  |               # else (if previous case is not (4))
    .*?           #   minimum of any chars
  )               # end if previous char is (4)
  (?(1)           # if comment (1)
    (?<=--)       #   wait for "--"
  )               # end if comment (1)
  (?(2)           # if another comment (2)
    (?<=\?)       #   wait for "?"
  )               # end if another comment (2)
  (?(3)           # if one of tags-containers (3)
    </            #   wait for end
    (?i:\3)       #   of this tag
    (?:\s[^>]*)?  #   skip junk to ">"
  )               # end if (3)
  >               # tag closed
 }{}gsx;         # STRIP THIS TAG

print;

__END__
<html><title>remove script, ul</title>
<script type="text/javascript"> 

function getCookies() { return ""; }

</script>
<body>
<ul><li>1
<li>2
<p>paragraph

输出

remove script, ul


1
2
paragraph

注意:此正则表达式不适用于嵌套标记容器,例如:

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Nested &lt;object> example</title>
<body>
<object data="uri:here">fallback content for uri:here
  <object data="uri:another">uri:another fallback
  </object>!!!this text should be striped too!!!
</object>

输出

Nested &lt;object> example

!!!this text should be striped too!!!

Don't parse html with regexs.使用html解析器或在其上构建的工具,例如HTML::Parser

#!/usr/bin/perl -w
use strict;
use warnings;

use HTML::Parser ();

HTML::Parser->new(
    ignore_elements => ["script"],
    ignore_tags => ["ul"],
    default_h => [ sub { print shift }, 'text'],
    )->parse_file(\*DATA) or die "error: $!\n";

__END__
<html><title>remove script, ul</title>
<script type="text/javascript"> 

function getCookies() { return ""; }

</script>
<body>
<ul><li>1
<li>2
<p>paragraph

输出

<html><title>remove script, ul</title>

<body>
<li>1
<li>2
<p>paragraph

答案 3 :(得分:0)

你必须要比这更谨慎。请参阅this answer中的两种方法。

答案 4 :(得分:0)

此:

$file =~ s/<div(.*)>//gi;

不会做你期望的。 '*'运算符是贪心的。如果你有一行:

hello<div id="foo"><b>bar!</b>baz

它将尽可能多地替代,只留下:

hellobaz

你想:

$file =~ s/<div[^>]*>//gi;

$file =~ s/<div.*?>//gi;