1

ifPerl 正規表現を使用する構成内で初期化されていない値を使用しないようにするにはどうすればよいですか?

以下のコードを使用すると、初期化されていない値のメッセージが使用されます。

     if($arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/)

以下のコードを使用すると、出力が得られません。

     if(defined($arrayOld[$i]) =~ /-(.*)/ || defined($arrayOld[$i]) =~ /\#(.*)/)

上記のコードで変数に値があるかどうかを確認する適切な方法は何ですか?

4

3 に答える 3

2

試す:

if($arrayOld[$i] && $arrayOld[$i] =~ /-|\#(.*)/)

これは、正規表現を実行する前に、最初に $arrayOld[$i] の値をチェックします。||( も正規表現に結合しました。)

于 2012-05-26T01:15:21.130 に答える
1

コメントのエラー メッセージから、@arrayOld定義されていない要素にアクセスしています。コードの残りの部分が表示されない場合、これはプログラムのバグを示しているか、予期された動作である可能性があります。

が である理由 を理解していて、警告を受けずにそれを許可したい場合$arrayOld[$i]undef、いくつかの方法があります。Perl 5.10.0 でdefined-or 演算子//が導入されました。これを使用して、 を空の文字列に置き換えることができますundef

use 5.010;
...
if(($arrayOld[$i] // '') =~ /-(.*)/ || ($arrayOld[$i] // '') =~ /\#(.*)/)

または、警告をオフにすることもできます。

if (do { no warnings 'uninitalized'; 
         $arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/ })

ここでは、警告が無効になる時間を制限するためにdoを使用しています。ただし、警告をオフにすると、 was の場合に表示される警告も抑制さ$iundefます。を使用//すると、何を許可するかundef、および の代わりにどの値を使用する必要があるかを正確に指定できますundef

注:は、定義されdefined($arrayOld[$i]) =~ /-(.*)/た関数の結果に対してパターン マッチを実行しています。これは、真/偽の値になります。テストしたい文字列ではありません。

于 2012-05-26T01:19:28.293 に答える
1

質問に狭く答えるために、そのコード行で未定義値の警告を防ぐことができます

if (defined $i && defined $arrayOld[$i]
      && ($arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/))
{
  ...;
}

つまり、$iまたは式のいずれかを評価する$arrayOld[$i]と、未定義の値になる可能性があります。&&との優先順位の違いにより、上記のように追加の括弧が必要になることに注意してください||。前者はより厳密に結合します。質問の特定のパターンについては、パターンを 1 つの正規表現に結合することでこの優先順位の問題を回避できますが、これは一般的なケースでは難しい場合があります。

上記の好ましくないコードは使用しないことをお勧めします。Perl が作業を行い、はるかに読みやすい、問題に対する洗練された解決策を確認するために読んでください。

思い返す

以前の質問の少し広い文脈から、$iはループ変数であり、構築により確実に定義されるため、テスト$iはやり過ぎです。あなたのコードはやみくもに から要素を引っ張ってきますが@arrayOld、Perl は喜んで義務付けます。何もない場合は、未定義の値が返されます。

この種の 1 つずつのぞき見や突っ込みは、C プログラムでは一般的ですが、Perl では、ほとんどの場合、アルゴリズムをよりエレガントに表現できるという危険信号です。以下の完全に機能する例を考えてみましょう。

作業デモンストレーション

#! /usr/bin/env perl

use strict;
use warnings;
use 5.10.0;  # given/when

*FILEREAD = *DATA;  # for demo only

my @interesting_line = (qr/-(.*)/, qr/\#(.*)/);

$/ = ""; # paragraph mode
while(<FILEREAD>) {
  chomp;
  my @arrayOld = split /\n/;
  my @arrayNewLines;

  for (1 .. @arrayOld) {
    given (shift @arrayOld) {
      push @arrayNewLines, $_ when @interesting_line;
      push @arrayOld, $_;
    }
  }

  print "\@arrayOld:\n",      map("$_\n", @arrayOld), "\n",
        "\@arrayNewLines:\n", map("$_\n", @arrayNewLines);
}

__DATA__
#SCSI_test         # put this line into  @arrayNewLines      
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd
- ccccccccccccccc  # put this line into @arrayNewLines

フロントの問題

この線

use 5.10.0;

Perl のgiven/ whenswitch ステートメントを有効にします。これにより、特定の入力行を取得する配列を決定する優れた方法が得られます。

コメントが示すように

*FILEREAD = *DATA;  # for demo only

これは、このスタック オーバーフローのデモンストレーションを目的としています。実際のコードでは、open FILEREAD, .... 質問からの入力を Perl のDATAファイルハンドルに配置すると、コードと入力を 1 つの自己完結型ユニットに表示できます。その後、エイリアスFILEREADを作成するDATAので、コードの残りの部分は問題なくあなたのものにドロップされます。

メインイベント

加工の肝は

for (1 .. @arrayOld) {
  given (shift @arrayOld) {
    push @arrayNewLines, $_ when @interesting_line;
    push @arrayOld, $_;
  }
}

definedチェックや明示的な正規表現の一致さえないことに注意してください! $iまたはありません$arrayOld[$i]!どうしたの?

@arrayOld現在の段落のすべての行を含めることから始めて、 の興味深い行で終了し、@arrayNewLines他のすべては にとどめたいとします@arrayOld。上記のコードは@arrayOldwithから次の行を取り出しshiftます。行が興味深い場合はpush、 の最後に移動し@arrayNewLinesます。それ以外の場合は、 の最後に戻し@arrayOldます。

ステートメント修飾子when @interesting_lineは、 のトピックとの暗黙的なスマート マッチを実行しgivenます。「スマート マッチングの詳細」で説明したように、配列に対してスマート マッチングを行うと、Perl は暗黙的にそれをループし、最初の一致で停止します。この場合、配列@interesting_lineには、移動先の行に一致するコンパイル済み正規表現が含まれています@arrayNewLines$_( のおかげで)現在の行givenがこれらのパターンのいずれとも一致しない場合は、 に戻り@arrayOldます。

前述のプロセスを正確にscalar @arrayOld1 回、つまり現在の段落の各行に対して 1 回実行します。このようにして、すべてを正確に 1 回処理し、現在の配列インデックスがどこにあるのかについて煩雑な簿記について心配する必要がなくなります。@arrayOldその多くの s の後に残っているものはすべて、その上に編集して戻しshiftた行でなければなりませんpush。これは、入力で発生した順序での興味深い行ではありません。

サンプル出力

質問の入力の場合、出力は

@arrayOld:
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd

@arrayNewLines:
#SCSI_test # この行を @arrayNewLines に入れます      
- ccccccccccccccc # この行を @arrayNewLines に入れます
于 2012-05-26T12:41:20.583 に答える