【问题标题】:perl get multiple lines from text file between patternperl 从模式之间的文本文件中获取多行
【发布时间】:2018-03-07 13:58:35
【问题描述】:

我有一个 html 文件,其中包含我必须推送到 MySql 数据库的数据。我尝试解析 html 文件以获取我需要的标量值,我做对了,但是当我到达需要收集数据而不是从单行文本而是从特定模式之间的多行中收集数据的地步时,我遇到了问题。 到目前为止,这是我得到的有点工作的东西:

  #!/usr/bin/perl
  binmode STDOUT,':encoding(cp1250)';

  open FILE, "index.html" or die "Could not open $file: $!";
  my $word;
  my $description;
  my $origin;

  while (my $line = <FILE>)
  { 
    if ($line =~ m/(?<=<h2 class=\"featured\">)(.*)(?=<\/h2>)/)
    {
    $word = $line =~ m/<=<h2 class=\"featured\">(.*)<\/h2>/;
    $word = $1;     
    }

    if ($line =~ m/(?<=<h4 class=\"related-posts\">)/)
    {
    print $line;
    $origin = $line =~ m/<h4 class=\"related-posts\"> <a href=\"..\/tag\/lacina\/index.html\" rel=\"tag\">(.*)<\/a><\/h4>/;
    $origin = $1;       
    }


  }

print "$word \n";
print "$origin";

现在我想抓取几行文本 - 不必是单个标量,但我不知道会有多少行。我所知道的是,这些线条介于以下之间:

<div class="post-content">

<p>text I want</p>
<p>1.text I want</p>
<p>2.text I want</p>

<div class="box small arial">

另外我想摆脱

       <p>'s

我想读取一行,将其存储在一个标量中,读取另一行并与最近保存的标量进行比较。但是我应该如何检查我是否在该标量中拥有我想要的一切?

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    使用工具代替正则表达式。

    use strict;
    use warnings;
    use feature 'say';
    use HTML::TreeBuilder;
    
    my $tr = HTML::TreeBuilder->new_from_file('index.html');
    
    for my $div ($tr->look_down(_tag => 'div', 'class' => 'post-content')) {
      for my $t ($div->look_down(_tag => 'p')) {
        say $t->as_text;
      }
    }
    

    输出

    text I want 1.text I want 2.text I want
    

    【讨论】:

    • 还有一件事:如何在目录树中使用这个脚本,所以我想搜索子文件夹并在每个 index.html 文件上运行这个脚本?
    • 您可以使用 File::Find 或 grep 来遍历子文件夹。这是example
    • 我包含了 File::Find,但我无法让 TreeBuilder 运行所有文件,它从同一个文件中读取:` my $tr = HTML::TreeBuilder->new_from_file('index.html ');我的 $location = "C:\\Users\\elesrog\\Desktop\\Dictionary\\Dictionary\\slownik\\"; sub find_txt { 对于我的 $div ($tr->look_down(_tag => 'div', 'class' => 'post-content')) { 对于我的 $t ($div->look_down(_tag => 'p ')) { 说 $t->as_text; } } find(\&find_txt, $location);`
    • 在我回到办公室之前给我一点。我去看看
    • 别担心——我搞定了!感谢您的帮助!
    【解决方案2】:

    使用range operator 查找两个模式之间的文本:

    use strict;
    use warnings;
    
    while (<DATA>) {
        if (my $range = /<div class="post-content">/ .. /<div class="box small arial">/) {
            next if $range =~ /E/;
            print;
        }
    }
    
    __DATA__
    <html>
    <head><title>stuff</title></head>
    <body>
    <div class="post-content">
    <p>text I want</p>
    <p>1.text I want</p>
    <p>2.text I want</p>
    </div>
    <div class="box small arial">
    </div>
    </body>
    </html>
    

    输出:

    <div class="post-content">
    <p>text I want</p>
    <p>1.text I want</p>
    <p>2.text I want</p>
    </div>
    

    然而,真正的答案是使用实际的 HTML Parser 来解析 HTML。

    我推荐Mojo::DOM。如需观看有用的 8 分钟介绍视频,请查看Mojocast Episode 5

    use strict;
    use warnings;
    
    use Mojo::DOM;
    
    my $data = do {local $/; <DATA>};
    
    my $dom = Mojo::DOM->new($data);
    
    for my $div ($dom->find('div[class=post-content]')->each) {
        print $div->all_text();
    }
    
    __DATA__
    <html>
    <head><title>stuff</title></head>
    <body>
    <div class="post-content">
    <p>text I want</p>
    <p>1.text I want</p>
    <p>2.text I want</p>
    </div>
    <div class="box small arial">
    </div>
    </body>
    </html>
    

    输出:

    text I want 1.text I want 2.text I want
    

    【讨论】:

    • 感谢全面的解释!我使用了 Mojo:DOM,但了解如何使用范围运算符将对我未来有很大帮助!
    猜你喜欢
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 2023-03-26
    相关资源
    最近更新 更多