【问题标题】:Using regex to extract URLs from plain text with Perl使用正则表达式从 Perl 的纯文本中提取 URL
【发布时间】:2009-06-27 18:07:51
【问题描述】:

如何使用 Perl 正则表达式从纯文本中提取具有特定扩展名的特定域(可能带有可变子域)的所有 URL?我试过了:

my $stuff = 'omg http://fail-o-tron.com/bleh omg omg omg omg omg http://homepage.com/woot.gif dfgdfg http://shomepage.com/woot.gif aaa';
while($stuff =~ m/(http\:\/\/.*?homepage.com\/.*?\.gif)/gmsi)
{
print $1."\n";
}

它严重失败并给了我:

http://fail-o-tron.com/bleh omg omg omg omg omg http://homepage.com/woot.gif
http://shomepage.com/woot.gif

我认为这不会发生,因为我使用的是.*?,它应该是非贪婪的并且给我最小的匹配。谁能告诉我我做错了什么? (我不想要一些超级复杂的罐装正则表达式来验证 URL;我想知道我做错了什么,以便从中吸取教训。)

【问题讨论】:

    标签: regex perl url


    【解决方案1】:

    URI::Find 是专门为解决这个问题而设计的。它将找到所有 URI,然后您可以过滤它们。它有一些启发式方法来处理诸如尾随标点符号之类的事情。

    更新:最近更新以处理 Unicode。

    【讨论】:

      【解决方案2】:

      访问CPANRegexp::Common::URI

      编辑:即使您不想要固定的正则表达式,它也可以帮助您查看经过测试的有效模块的源代码。

      如果你想找到匹配某个字符串的 URL,你可以很容易地使用这个模块来做到这一点。

      #!/usr/bin/env perl
      use strict;
      use warnings;
      use Regexp::Common qw/URI/;
      
      while (<>) {
        if (m/$RE{URI}{HTTP}{-keep}/) {
          print $_ if $1 =~ m/what-you-want/;
        }
      }
      

      【讨论】:

        【解决方案3】:

        我已使用以下代码提取以特定扩展名结尾的链接
        如 *.htm、*.html、*.gif、*.jpeg。 注意:在这个脚本扩展中,先写 *.html,然后写 *.htm,因为两者都有“htm”。因此,此类更改应谨慎进行。

        输入:具有链接的文件名和将保存结果的输出文件名。
        输出: 将保存在输出文件中。

        代码在这里:

        use strict;
        use warnings;
        
        if ( $#ARGV != 1 ) {
        print
        "Incorrect number of arguments.\nArguments: Text_LinkFile, Output_File\n";
        die $!;
        }
        open FILE_LINKS, $ARGV[0] or die $!;
        open FILE_RESULT, ">$ARGV[1]" or die $!;
        
        my @Links;
        foreach (<FILE_LINKS>) {
            my @tempArray;
            my (@Matches) =( $_ =~ m/((https?|ftp):\/\/[^\s]+\.(html?|gif|jpe?g))/g );
            for ( my $i = 0 ; $i < $#Matches ; $i += 3 ) {
                push( @Links, $Matches[$i] );
                }
            }
        print FILE_RESULT join( "\n", @Links );
        

        您的字符串的输出在这里:

        http://homepage.com/woot.gif
        http://shomepage.com/woot.gif
        

        【讨论】:

        • 为什么不用(html?|gif|jpe?g) 而不是(html|htm|gif|jpeg|jpg)
        • @BradGilbert:是的,这样更好:)
        • 我也想加入 (https?|ftp) 作为更改,但除此之外它有效
        • @VarLogRant 是的,这样更好。
        【解决方案4】:

        网址不允许包含空格,所以用 .*?对于零个或多个非空格字符,您应该使用 \S*?。

        【讨论】:

        • RFC 3986 Appendix C 讨论了提取 URI 的特殊问题,包括允许空格的情况。 “在某些情况下,可能必须添加额外的空格(空格、换行符、制表符等)来打破跨行的长 URI。提取 URI 时应忽略空格。”并且“为了稳健性,接受用户键入的 URI 的软件应该尝试识别和去除分隔符和嵌入的空格。”也就是说,根据经验,这很困难。
        【解决方案5】:
        https?\:\/\/[^\s]+[\/\w]
        

        这个正则表达式对我有用

        【讨论】:

        • 多一点上下文和/或解释会很好。
        【解决方案6】:

        我认为这不应该发生,因为我使用的是 .*?这应该是非贪婪的,并给我最小的匹配

        确实如此,但它会为您提供最小的匹配正确。从第一个http 开始往右走,这是最小的匹配。

        请注意以后,您不必转义斜线,因为您不必使用斜线作为分隔符。而且您也不必逃避冒号。下次只需这样做:

        m|(http://.*?homepage.com\/.*?\.gif)|
        

        m#(http://.*?homepage.com\/.*?\.gif)#
        

        m<(http://.*?homepage.com\/.*?\.gif)>
        

        或许多其他字符之一,请参阅 perlre 文档。

        【讨论】:

          【解决方案7】:

          这是一个(希望)从字符串|文本文件中获取|提取|获取所有 URL 的正则表达式,这似乎对我有用:

          m,(http.*?://([^\s)\"](?!ttp:))+),g
          

          ...或者举个例子:

          $ echo -e "\n\na blahlah blah:http://www.abc.com/dss.htm?a=1&p=2#chk - blahblah \"https://poi.com/a%20b\"; (http://bbb.comhttp://roch.com/abc) \n" | perl -ne 'while ( my $string = <> ) { print "$string\n"; while ( $string =~ m,(http.*?://([^\s)\"](?!ttp:))+),g ) {print "$&\n"} }'
          
          
          a blahlah blah:http://www.abc.com/dss.htm?a=1&p=2#chk - blahblah "https://poi.com/a%20b"; (http://bbb.comhttp://roch.com/abc) 
          
          http://www.abc.com/dss.htm?a=1&p=2#chk
          https://poi.com/a%20b
          http://bbb.com
          http://roch.com/abc
          

          对于我的菜鸟参考,这里是上面相同命令的调试版本:

          $ echo -e "\n\na blahlah blah:http://www.abc.com/dss.htm?a=1&p=2#chk - blahblah \"https://poi.com/a%20b\"; (http://bbb.comhttp://roch.com/abc) \n" | perl -dne 'use re "debug" ; while ( my $string = <> ) { print "$string\n"; while ( $string =~ m,(http.*?://([^\s)\"](?!ttp:))+),g ) {print "$&\n"} }'
          

          正则表达式匹配http(s):// - 并使用空格、") 作为“退出”字符;然后使用positive lookahead 最初在“http”文字组上导致“退出”(如果匹配已经在进行中);然而,由于这也“吃掉”了前一场比赛的最后一个字符,所以这里的前瞻匹配向前移动了一个字符到“ttp:”。

          一些有用的页面:

          希望这对某人有所帮助,
          干杯!

          编辑:Ups,刚刚发现 URI::Find::Simple - search.cpan.org,似乎也在做同样的事情(通过 regex - Getting the website title from a link in a string

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-09-14
            • 2010-12-20
            • 2011-02-07
            • 1970-01-01
            • 2015-01-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多