【问题标题】:Calculate Number of Consecutive Characters in a String using Perl使用 Perl 计算字符串中的连续字符数
【发布时间】:2012-06-10 13:54:36
【问题描述】:

我有一个包含多个连续字符序列的字符串,例如:

aaabbcccdddd

我想将其表示为:a3b2c3d4

到目前为止,我想出了这个:

#! /usr/bin/perl

$str = "aaabbcccdddd";
$str =~ s/(.)\1+/$1/g;

print $str."\n";

输出:

abcd

它将连续的字符存储在捕获缓冲区中,并且只返回一个。但是,我想要一种方法来计算捕获缓冲区中连续字符的数量,然后只显示一个字符,然后显示该计数,以便将输出显示为 a3b2c3d4 而不是 abcd

上面的正则需要什么修改?

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    这似乎需要替换命令上的“执行”选项,因此替换文本被视为 Perl 代码的片段:

     $str =~ s/((.)\2+)/$2 . length($1)/ge;
    

    脚本

    #!/usr/bin/env perl
    use strict;
    use warnings;
    
    my $original = "aaabbcccdddd";
    my $alternative = "aaabbcccddddeffghhhhhhhhhhhh";
    
    sub proc1
    {
        my($str) = @_;
        $str =~ s/(.)\1+/$1/g;
        print "$str\n";
    }
    
    proc1 $original;
    proc1 $alternative;
    
    sub proc2
    {
        my($str) = @_;
        $str =~ s/((.)\2+)/$2 . length($1)/ge;
        print "$str\n";
    }
    
    proc2 $original;
    proc2 $alternative;
    

    输出

    abcd
    abcdefgh
    a3b2c3d4
    a3b2c3d4ef2gh12
    

    能否请您分解正则表达式来解释它是如何工作的?

    我假设是匹配部分有问题,而不是替换部分。

    原来的正则表达式是:

    (.)\1+
    

    这会捕获单个字符 (.),后面跟着相同的字符重复一次或多次。

    修改后的正则表达式“相同”,但也捕获了整个模式:

    ((.)\2+)
    

    第一个左括号开始整体捕获;第二个左括号开始捕获单个字符。但是,现在是第二次捕获,所以原来的\1需要修改成\2

    由于搜索捕获了整个重复字符的字符串,替换可以很容易地确定模式的长度。

    【讨论】:

      【解决方案2】:

      如果您可以忍受$& 造成的减速,则以下工作:

      $str =~ s/(.)\1*/$1. length $&/ge;
      

      将上述表达式中的* 更改为+ 不会影响非连续字符。

      正如 JRFerguson 提醒的那样,Perl 5.10+ 提供了一个等效的 ${^MATCH} 变量,它不会影响正则表达式的性能:

      $str =~ s/(.)\g{1}+/$1. length ${^MATCH}/pge;
      

      对于 Perl 5.6+,仍然可以避免性能损失:

      $str =~ s/(.)\g{1}+/ $1. ( $+[0] - $-[0] ) /ge;
      

      【讨论】:

      • 感谢您的快速回答。我将学习更多关于正则表达式的知识:)
      • Perl 5.10 引入了${^MATCH} 以避免$& 的性能损失。见perlre
      • 要限制性能影响,请将 '\p' 修饰符添加到匹配项中。然后,${^PREMATCH" ${^MATCH}${^POSTMATCH} 仅针对有问题的匹配被捕获,而不是每一个。
      • @JRFerguson :在这种情况下,我认为这对最终结果没有任何影响。
      • 似乎有一个串行驱动的非评论投票者;有人不喜欢您和我给出的解决方案,但不准备花时间提供他们自己更好的解决方案或评论为什么有理由投反对票。这很麻烦;它发生了;除了互相同情,我们都无能为力。
      【解决方案3】:

      JS:

      let data = "ababaaaabbbababb";
      
      data.replace(/((.)\2+)/g, (match, p1, p2) =>  {
        data = data.replace(new RegExp(p1, 'g'), p2 + p1.length);
      });
      
      console.log(data);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多