- ベストアンサー
perl初心者です。
perl初心者です。 正規表現で記載された下記のような文字列を以下のように書き換えたいのです。 server0[123] client[1-3][0-9] ↓↓ server01,server02,server03 client10,client11........client38,client39 よろしくお願いします
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
インデントがずれるので、以下のコードで空白を一部全角にしてありま す。動かすときは全角の空白を半角の空白2文字にして下さい。 my $code; my $code_ref; my $server = 'server0[123]'; $code = create_code($server); print $code; $code_ref = eval "sub { $code }"; print join( ', ', $code_ref->() ), $/; my $client = 'client[1-3][0-9]'; $code = create_code($client); print $code; $code_ref = eval "sub { $code }"; print join( ', ', $code_ref->() ), $/; sub create_code { my $str = shift; my $regexp = $str; my $count = ( $regexp =~ s/\[([^\]]+)\]/\\[([^\]]+)\\]/g ); my $code = ''; $code .= "if ( \"$str\" =~ /$regexp/ ) {\n"; $code .= ' ' x 4; $code .= "my \@list = ();\n"; for ( my $i = 1; $i <= $count; $i++ ) { $code .= ' ' x ( $i * 4 ); $code .= "for my \$num$i (expand_num_regexp(\${$i})) {\n"; } my $i = 1; while ( $str =~ s/\[([^\]]+)\]/'${num' . $i++ . '}'/eg ) { ; } $code .= ' ' x ( ( $count + 1 ) * 4 ); $code .= "push \@list, \"$str\";\n"; for ( my $i = $count; 0 < $i; $i-- ) { $code .= ' ' x ( $i * 4 ); $code .= "}\n"; } $code .= ' ' x 4; $code .= "return \@list\n}\n"; return $code; } sub expand_num_regexp { my $num_regexp = shift; while ( $num_regexp =~ s/([0-9])-([0-9])/join '', ($1 .. $2)/eg ) { ; } if ( $num_regexp =~ /^[0-9]+$/ ) { return split '', $num_regexp; } }
その他の回答 (2)
- kumoz
- ベストアンサー率64% (120/185)
client0[1-35-7] や client0[13-69] にも対応できるよう少し修正しました。これで、server0[123] も含めて展開できると思います。 use strict; my $reg_str = 'client0[1-35-7]'; my $head = substr $reg_str, 0, index($reg_str, '['); my ($num) = $reg_str =~ /\[([\d-]+)\]/; # /\[(\d+)\]/ から /\[([\d-]+)\]/ に変更 $num =~ s/(\d)-(\d)/join('', $1 .. $2)/eg; # この行を追加 my @num = split //, $num; my @result; foreach my $i (@num) { push @result, "$head$i"; } print join(',', @result), "\n"; 次のプログラムは、上のプログラムを修正して複数の文字クラスでも展開できるようにしたものです。 質問に出てきた例は、すべて展開できると思います。 use strict; my @reg_str = ('server0[123]', 'client0[1-35-7]', 'client0[13-69]', 'client[1-3][0-9]'); my (@work, @result); foreach my $reg_str (@reg_str) { print "$reg_str\n"; my $head = substr($reg_str, 0, index($reg_str, '[')); my @num = map { s/(\d)-(\d)/join('', $1 .. $2)/eg; [split //] } $reg_str =~ /\[([\d-]+)\]/g; @result = (); comb(@num); print join(',', map { $head . $_ } @result), "\n\n"; } sub comb { my $ref = shift; foreach my $i (@$ref) { push @work, $i; unless (@_) { push @result, join('', @work); } else { comb(@_); } pop @work; } }
- kumoz
- ベストアンサー率64% (120/185)
まずは、それぞれの正規表現文字列を展開するプログラムを考えてはどうでしょうか。 次のプログラムで、server0[123] を展開できると思います。先頭の固定文字列を変数に、 文字クラスの各文字を配列に入れて、foreach ループでつなぎ合わせているだけです。 use strict; my $reg_str = 'server0[123]'; my $head = substr $reg_str, 0, index($reg_str, '['); my ($num) = $reg_str =~ /\[(\d+)\]/; # my ($num1, $num2) = $reg_str =~ /\[([\d-]+)\]/g; my @num = split //, $num; # my @num1 = substr($num1, 0, 1) .. substr($num1, -1); (@num2 も同様) my @result; foreach my $i (@num) { push @result, "$head$i"; } print join(',', @result), "\n"; 少々複雑になりますが、client[1-3][0-9] も同じような方法で展開できます。上のコードで、 コメントとして記してあるのが client[1-3][0-9] 用の文です。foreach を2段重ねにすれば 展開できると思います。
補足
早速のご回答ありがとうございました。 client0[1-35-7] client0[13-69] のパターンの場合がうまくいきません。 また、client部分は随時名称が変わります。 お礼が遅くなってスイマセン。 OKWEBも初心者なもので。。。 お時間がございましたらよろしくお願いします。
お礼
お忙しいであろう中、迅速なご回答ありがとうございました。 非常に助かりました。 また、わかりやすい回答でたすかりました。