• ベストアンサー

perl初心者です。

perl初心者です。 正規表現で記載された下記のような文字列を以下のように書き換えたいのです。 server0[123] client[1-3][0-9] ↓↓ server01,server02,server03 client10,client11........client38,client39 よろしくお願いします

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

インデントがずれるので、以下のコードで空白を一部全角にしてありま す。動かすときは全角の空白を半角の空白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)
回答No.3

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; } }

koga8940
質問者

お礼

お忙しいであろう中、迅速なご回答ありがとうございました。 非常に助かりました。 また、わかりやすい回答でたすかりました。

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.2

まずは、それぞれの正規表現文字列を展開するプログラムを考えてはどうでしょうか。 次のプログラムで、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段重ねにすれば 展開できると思います。

koga8940
質問者

補足

早速のご回答ありがとうございました。 client0[1-35-7] client0[13-69] のパターンの場合がうまくいきません。 また、client部分は随時名称が変わります。 お礼が遅くなってスイマセン。 OKWEBも初心者なもので。。。 お時間がございましたらよろしくお願いします。

関連するQ&A

専門家に質問してみよう