7

次のような連続した文字の複数のシーケンスを含む文字列があります。

aaabbcccdddd

これを次のように表現したい:a3b2c3d4

今のところ、私はこれを思いつきました:

#! /usr/bin/perl

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

print $str."\n";

出力:

abcd

連続する文字をキャプチャ バッファーに格納し、1 つだけを返します。ただし、キャプチャ バッファー内の連続する文字の数をカウントし、1 文字だけを表示し、その後にそのカウントを表示して、出力を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+

(.)これは、同じ文字が 1 回以上繰り返される単一の文字をキャプチャします。

改訂された正規表現は「同じ」ですが、パターン全体もキャプチャします。

((.)\2+)

最初の開き括弧は、全体のキャプチャーを開始します。2 番目の開き括弧は、1 文字のキャプチャを開始します。ただし、現在は 2 番目のキャプチャであるため、\1オリジナル\2の はリビジョンである必要があります。

検索では繰り返される文字の文字列全体がキャプチャされるため、置換によってパターンの長さを簡単に判断できます。

于 2012-06-10T14:08:08.250 に答える
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 に答える
1

によるスローダウンに耐えられる場合は、次のように動作します$&

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

*上記の式でtoを変更すると+、連続していない文字は変更されません。

JRFerguson が思い出すように、Perl 5.10+ は${^MATCH}正規表現のパフォーマンスに影響を与えない同等の変数を提供します:

$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 に答える