7

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

aaabbcccdddd

我想将其表示为:a3b2c3d4

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

#! /usr/bin/perl

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

print $str."\n";

输出:

abcd

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

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

4

3 回答 3

11

这似乎需要替换命令上的“执行”选项,因此替换文本被视为 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修改版中的。

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

于 2012-06-10T14:08:08.250 回答
1

如果您可以忍受由以下原因引起的减速,则以下工作有效$&

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

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

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

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

对于 Perl 5.6+,仍然可以避免性能下降:

$str =~ s/(.)\g{1}+/ $1. ( $+[0] - $-[0] ) /ge;
于 2012-06-10T14:18:45.193 回答
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);
于 2017-01-25T14:10:39.693 回答