1

次のような詳細を含むファイルがあります。

/var/example/12.1.1.0-gn/product
/var/example/12.1.1.0-xn/product
              .
              .
/var/example/13.1.1.0-gn/product
/var/example/13.1.1.0-xn/product

上記のパスを使用して、次のような新しい変数を挿入したいと思います。

/var/example/12.1.1.0/12.1.1.0-gn/製品
/var/example/12.1.1.0/12.1.1.0-xn/product
              .
              .
/var/example/13.1.1.0/13.1.1.0-gn/製品
/var/example/13.1.1.0/13.1.1.0-xn/product

私はそれのために以下のスクリプトを書きました:

ここ$new_addで、 は新しいパーツに追加されたパーツを表します。スクリプトを一般化するために、正規表現を介して実行しようとしています。私はperlの初心者なので、どこか間違っていたら教えてください。ありがとうございました。

open (FH) or dir ("Could not open the file");
foreach $line (<FH>){
     ($a, $b, $c, $d, $e, $f) = split ('/', $line);
      chomp ($line);
      print "$a, $b, $c, $d $e $f\n";
      if ($e =~ m/^\d.\d.\d.\d-\d+/){
          $new_add = $e;
          print "Match";
      }
 }
4

3 に答える 3

4

あなたの Perl スタイルは Perl 4 に基づいています。いくつかのより良いプラクティスを採用すると、Perl の作成作業がずっと楽になります。まず、問題の簡単な解決策:

#!/usr/bin/perl -np
use strict;
use warnings;
s{/(\d+\.\d+\.\d+\.\d+)-}{/$1/$1-};

これは、4 部構成のバージョン文字列と一致し、それをキャプチャして、ディレクトリ パスの別の要素にします。ここで、スクリプトに対処し、より優れた Perl を示します。

まず、常に常にスクリプトを で開始しますuse strict; use warnings;。これにより、スクリプトの解釈がより厳密になります。これは素晴らしいことです。なぜなら、Perl は通常、必要なものを知っていると想定し、エラーの発生を回避するために可能な限りのことを行うからです。最も目に見えるのは、レキシカル スコープuse strict;を強制することです。これは、変数を で宣言する必要があることを意味します。my

したがって、最初の行( の後use strict; use warnings;)は次のとおりです。

open (FH) or dir ("Could not open the file");

Perl は、いくつかのことについて文句を言うようになりました。まず、ファイル ハンドルは変数です。したがって、次のように宣言する必要がありますmy $fh。小文字の変数名を使用してください。それはより読みやすいです。Perl はまた、そのベアワードも好きではありませんdir。私はあなたdieがキーワードであるを意味したと思います:

open my $fh or die "Could not open the file";

わかりましたので、不要な括弧をいくつか削除して、行をより読みやすくしました。しかし、今ではファイルを開くことができません。これは、ファイル名を指定していないためです。の使用方法は多数ありますopenが、ほとんどの目的に最適な方法は 3 引数形式です。引数は、 filehandlemode、およびfilenameです。この場合、ファイルから読み取りたいので、モード"<"次のとおりです。

open my $fh, "<", "test.txt" or die "Could not open the file";

use autodie;これは、スクリプトの先頭に含めることにより、エラー処理を Perl に任せることができることを指摘するのに良い時期です。スクリプトは次のようになります。

#!/usr/bin/perl

use strict; 
use warnings;
use autodie;

open my $fh, "<", "test.txt";

foreach my $line (<$fh>){

Now,foreachは の同義語ですがfor、入力の手間が省けるので私はこちらの方が好みです。$lineがレキシカルに宣言され ( my)、ひし形演算子 ( <>) がレキシカル ファイルハンドルを囲んでいます$fh。残念ながら、これによりファイル全体がメモリに読み込まれるため、問題が発生する可能性があります。代わりにループを使用すると、whileループを通過するときに各行が保存、処理、破棄されます。

while (my $line = <$fh>) {
    ($a, $b, $c, $d, $e, $f) = split ('/', $line);

これを見てください!レキシカルスコープが必要な変数がたくさんあります。1 つの方法はmy、それらすべてに対して 1 つの宣言を使用することですmy ($a, $b, $c, $d, $e, $f)。より良いアイデアは、似たような一連のアイテムがあることに気付くことです. これはおそらく、配列を使用してより適切に記述できます。

my @path = split '/', $line;

そこ、いいね!なぜchomp次の行に決めたのかわかりません。この後は使わないので意味がない$lineので飛ばします。新しい@path変数を使用するには、次の行を変更する必要があります。

print join(", ", @path), "\n";

を使用joinすると、行を分割する要素の数を知る必要がなくなります。また、(この出力から) の 4 番目の要素 (インデックス 3) が@path、一致させたいバージョン文字列を持つものであることもわかりますが、正規表現は少しずれています。

if ($path[3] =~ m/^\d.\d.\d.\d-\d+/){

これは、任意の文字で区切られた一連の 1 桁の数字と、「-」の後にさらに数字が続くものを探しています。あなたの例は、これらのいくつかは複数の数字である必要があり、リテラル「。」と一致する必要があることを示しています。(ピリオド、ピリオド) 正規表現の代わりに "." (任意の文字)、最後の部分は文字 ("xn"、"gn" など) にすることができます。これに一致する正規表現は次のとおりです。

if ($path[3] =~ m/^(\d+\.\d+\.\d+\.\d+)-../){

+「1 つ以上」を意味し、文字\をエスケープするために追加したことに気付くでしょう。もう 1 つ、ディレクトリ名として必要なバージョン文字列を残りの文字列とは別に取得するために、.グループ化括弧を追加しました。このキャプチャは変数に()格納されるため、次の行は次のようになります。$1

my $new_add = $1;

そしてそれはそれについてです。もちろん、スクリプトを完成させるにはさらに多くの作業が必要になりますが、Perl のエクスペリエンスを向上させるためのツールを提供できれば幸いです。そして、あなたが望んでいたのが迅速な解決策だけだった場合、それは一番上にあります.

Perl でプログラミングを続けたい場合は、Perl 5 について説明している本を入手することをお勧めします。できれば過去 5、6 年以内に書かれた本を入手してください。私が強くお勧めするのは、オンラインでも無料で入手できるModern Perlです。

于 2013-05-21T02:47:18.633 に答える
0
use strict;
use warnings;

while (my $line = <>){
    my (@v) = split ('/', $line);
    print join(" ", @v), "\n";
    if (my ($new_add) = $v[-2] =~ m/([^-]*)/){
        print "Match $new_add\n";
    }   
}
于 2013-05-21T01:58:08.953 に答える