2

この質問に答えようとしているときに、Perl の正規表現エンジンの奇妙な動作に遭遇しました。正規表現と一致させようとしている 2 つの数量を含む文字列があります。正規表現は、文字列「units/ml」の前の任意の 8 文字と一致します。両方のユニットを手に入れたいです。

このスクリプトは、一致した 2 番目のもののみを出力します。

use warnings;
use strict;
my $line = 'some data 100,000 units/ml data 20,000 units/ml data';
my @array;
if ($line =~ m/.{8}units\/ml/g) {
    @array = $line =~ m/.{8}units\/ml/g;
    print join(' ', @array) . "\n";
}

その出力:

 20,000 units/ml

行 6 を 2 回実行すると、@array に割り当てる行:

use warnings;
use strict;
my $line = 'some data 100,000 units/ml data 20,000 units/ml data';
my @array;
if ($line =~ m/.{8}units\/ml/g) {
    @array = $line =~ m/.{8}units\/ml/g;
    # Let's run that again, for good measure...
    @array = $line =~ m/.{8}units\/ml/g;
    print join(' ', @array) . "\n";
}

その出力:

100,000 units/ml  20,000 units/ml

これら 2 つのスクリプトで異なる結果が得られるのはなぜですか?

4

3 に答える 3

3

これは、if の /g 修飾子が原因です。if はスカラー コンテキストで =~ を評価しているため、一致した最初の項目のみを取得します。次に、if ブロック内で、@array の割り当てにより、中断したところから検索が続行されます。(これは解析に役立ちます。)

追加の一致を実行すると、文字列内のすべての一致が既に終了しているため、リスト コンテキストで最初からやり直すと、すべてが得られます。

if で g フラグを削除すると、期待どおりに機能します。

于 2012-08-14T23:11:01.107 に答える
1

この場合のオプションは、ifステートメント内の配列割り当てを評価することです。

use Modern::Perl;

my $line = 'some data 100,000 units/ml data 20,000 units/ml data';
my @array;
if ( @array = $line =~ m/.{8}units\/ml/g ) {
    print join( ' ', @array ) . "\n";
}

出力:

100,000 units/ml  20,000 units/ml

また、一致が発生しなかった場合は、必要に応じて適切なアクションを実行できます。

于 2012-08-14T23:56:34.400 に答える
0

問題はここにあります

if ($line =~ m/.{8}units\/ml/g) { ... }

スカラー コンテキストでのグローバル マッチは、パターンの次の出現にマッチし、次のグローバル マッチの開始位置を示すマークを設定します。

20,000 units/mlあとはパターンにマッチするものしか残っていないので、1回だけマッチします

文字列内のすべての数字またはカンマを収集するには、次のunits/mlように記述します。

use strict;
use warnings;

my $line = 'some data 100,000 units/ml data 20,000 units/ml data';

my @array = $line =~ m|([0-9,]+)\s*units/ml|g;

print "$_\n" for @array;

出力

100,000
20,000
于 2012-08-15T01:27:45.337 に答える