我有一个包含多个连续字符序列的字符串,如:
aaabbcccdddd
我想将其表示为:a3b2c3d4
截至目前,我已经提出了这个问题:
#! /usr/bin/perl
$str = "aaabbcccdddd";
$str =~ s/(.)\1+/$1/g;
print $str."\n";
输出:
abcd
它将连续字符存储在捕获缓冲区中,并仅返回一个字符。但是,我想要一种方法来计算捕获缓冲区中连续字符的数量,然后只显示一个字符,然后显示该计数,以便它将输出显示为a3b2c3d4
而不是abcd
。
上述正则表达式需要进行哪些修改?
答案 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);