【问题标题】:Perl Regular Expression to insert/substitute in a string at specific placesPerl 正则表达式在特定位置插入/替换字符串
【发布时间】:2013-02-16 04:13:12
【问题描述】:

给定一个 url,以下正则表达式可以在 url 的某些点插入/替换单词。

代码:

#!/usr/bin/perl

use strict;
use warnings;
#use diagnostics;

my @insert_words = qw/HELLO GOODBYE/;
my $word = 0;
my $match;

while (<DATA>) {
    chomp;
    foreach my $word (@insert_words)
    {
        my $repeat = 1;
        while ((my $match=$_) =~ s|(?<![/])(?:[/](?![/])[^/]*){$repeat}[^/]*\K|$word|)
        {
            print "$match\n";
            $repeat++;
        }

    print "\n";
    }
}

__DATA__
http://www.stackoverflow.com/dog/cat/rabbit/
http://www.superuser.co.uk/dog/cat/rabbit/hamster/
10.15.16.17/dog/cat/rabbit/

给出的输出(__DATA__ 中的第一个示例 url 带有 HELLO 字):

http://www.stackoverflow.com/dogHELLO/cat/rabbit/
http://www.stackoverflow.com/dog/catHELLO/rabbit/
http://www.stackoverflow.com/dog/cat/rabbitHELLO/
http://www.stackoverflow.com/dog/cat/rabbit/HELLO

我现在卡住的地方:

我现在想更改正则表达式,使输出如下所示:

http://www.stackoverflow.com/dogHELLO/cat/rabbit/
http://www.stackoverflow.com/dog/catHELLO/rabbit/
http://www.stackoverflow.com/dog/cat/rabbitHELLO/
http://www.stackoverflow.com/dog/cat/rabbit/HELLO
#above is what it already does at the moment
#below is what i also want it to be able to do as well
http://www.stackoverflow.com/HELLOdog/cat/rabbit/  #<-puts the word at the start of the string
http://www.stackoverflow.com/dog/HELLOcat/rabbit/
http://www.stackoverflow.com/dog/cat/HELLOrabbit/
http://www.stackoverflow.com/dog/cat/rabbit/HELLO
http://www.stackoverflow.com/HELLO/cat/rabbit/  #<- now also replaces the string with the word
http://www.stackoverflow.com/dog/HELLO/rabbit/
http://www.stackoverflow.com/dog/cat/HELLO/
http://www.stackoverflow.com/dog/cat/rabbit/HELLO

但我无法让它在一个正则表达式中自动执行此操作。

非常感谢您对此事的任何帮助,非常感谢

【问题讨论】:

  • 你的意思是把/dog/cat/rabbit/HELLO放两次吗?
  • @ikegami - 好问题,我希望它不要重复,我把它留在问题中,以便其他人可以更轻松地理解我想要实现的输出类型,谢谢
  • 这可能不是正则表达式的工作,而是您选择的语言的现有工具。您使用什么语言?您可能不想使用正则表达式,而是使用已经编写、测试和调试过的现有模块。如果您使用的是 PHP,则需要 parse_url 函数。如果您使用 Perl,则需要 URI 模块。如果您使用的是 Ruby,请使用 URI 模块。
  • 我正在使用perl,谢谢你的建议,我不知道我没有使用URI模块是怎么过的,谢谢
  • @AndyLester - 我假设我需要使用 perl URI::Escapeuri_unescape($url) 在我的 arrayref 数据结构中以更“人类可读”的形式查看 URL,当它们被打印到 STDOUT 时,因为我的网址中的许多字符都是百分比编码的。但是,在实际使用 LWP::UserAgent 获取特定 url 时,最好使用 uri_escape($url) 对字符进行百分比编码

标签: regex string perl substitution string-substitution


【解决方案1】:

一个解决方案:

use strict;
use warnings;

use URI qw( );

my @insert_words = qw( HELLO );

while (<DATA>) {
   chomp;
   my $url = URI->new($_);
   my $path = $url->path();

   for (@insert_words) {
      # Use package vars to communicate with /(?{})/ blocks.
      local our $insert_word = $_;
      local our @paths;
      $path =~ m{
         ^(.*/)([^/]*)((?:/.*)?)\z
         (?{
            push @paths, "$1$insert_word$2$3";
            if (length($2)) {
               push @paths, "$1$insert_word$3";
               push @paths, "$1$2$insert_word$3";
            }
         })
         (?!)
      }x;

      for (@paths) {
         $url->path($_);
         print "$url\n";
      }
   }
}

__DATA__
http://www.stackoverflow.com/dog/cat/rabbit/
http://www.superuser.co.uk/dog/cat/rabbit/hamster/
http://10.15.16.17/dog/cat/rabbit/

【讨论】:

    【解决方案2】:

    没有疯狂的正则表达式:

    use strict;
    use warnings;
    
    use URI qw( );
    
    my @insert_words = qw( HELLO );
    
    while (<DATA>) {
       chomp;
       my $url = URI->new($_);
       my $path = $url->path();
    
       for my $insert_word (@insert_words) {
          my @parts = $path =~ m{/([^/]*)}g;
          my @paths;
          for my $part_idx (0..$#parts) {
             my $orig_part = $parts[$part_idx];
             local $parts[$part_idx];
             {
                $parts[$part_idx] = $insert_word . $orig_part;
                push @paths, join '', map "/$_", @parts;
             }
             if (length($orig_part)) {
                {
                   $parts[$part_idx] = $insert_word;
                   push @paths, join '', map "/$_", @parts;
                }
                {
                   $parts[$part_idx] = $orig_part . $insert_word;
                   push @paths, join '', map "/$_", @parts;
                }
             }
          }
    
          for (@paths) {
             $url->path($_);
             print "$url\n";
          }
       }
    }
    
    __DATA__
    http://www.stackoverflow.com/dog/cat/rabbit/
    http://www.superuser.co.uk/dog/cat/rabbit/hamster/
    http://10.15.16.17/dog/cat/rabbit/
    

    【讨论】:

    • 摆脱这个解决方案的正则表达式的好主意,谢谢,它也会让我在程序的其余部分的生活变得更轻松。
    • 不知道哪个更快,如果这很关键。
    • 我知道我需要将正则表达式更改为 my @parts = $path =~ m{[/=&amp;]([^/=&amp;]*)}g; 以使其与我指定的其他字符 (/=&) 分开,而不仅仅是斜杠。但我不知道接下来要改变什么,因为map "/$_", @parts; 显然总是用斜线输出它,即使它是在 url 中找到的 =&amp;?非常感谢您的帮助
    【解决方案3】:

    另一种解决方案:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my @insert_words = qw/HELLO GOODBYE/;
    
    while (<DATA>) {
        chomp;
        /(?<![\/])(?:[\/](?![\/])[^\/]*)/p;
        my $begin_part = ${^PREMATCH};
        my $tail = ${^MATCH} . ${^POSTMATCH};
        my @tail_chunks = split /\//, $tail; 
    
        foreach my $word (@insert_words) {                      
            for my $index (1..$#tail_chunks) {
                my @new_tail = @tail_chunks;
    
                $new_tail[$index] = $word . $tail_chunks[$index];
                my $str = $begin_part . join "/", @new_tail;
                print $str, "\n";
    
                $new_tail[$index] = $tail_chunks[$index] . $word;
                $str = $begin_part . join "/", @new_tail;  
                print $str, "\n";
            }
    
            print "\n";
        }
    }
    
    __DATA__
    http://www.stackoverflow.com/dog/cat/rabbit/
    http://www.superuser.co.uk/dog/cat/rabbit/hamster/
    10.15.16.17/dog/cat/rabbit/
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-19
      • 1970-01-01
      • 1970-01-01
      • 2014-05-25
      • 1970-01-01
      • 2021-12-19
      • 2021-11-20
      相关资源
      最近更新 更多