使用Perl计算字符串中的连续字符数

时间:2012-06-10 13:54:36

标签: regex perl

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

aaabbcccdddd

我想将其表示为:a3b2c3d4

截至目前,我已经提出了这个问题:

#! /usr/bin/perl

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

print $str."\n";

输出:

abcd

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

上述正则表达式需要进行哪些修改?

3 个答案:

答案 0 :(得分:10)

这似乎需要在substitute命令中使用'execute'选项,因此替换文本被视为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

因为搜索会捕获整个重复字符串,所以替换可以轻松确定模式的长度。

答案 1 :(得分:1)

如果您可以忍受由$&

引起的减速,则以下情况有效
$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;

答案 2 :(得分:1)

JS:

let data = "ababaaaabbbababb";

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

console.log(data);