2
09/27/2009 19:48:00 Departure Location

テキストファイル内の指定された行を一致させて置き換えようとしています。日付と時刻の後のテキストの長さはさまざまです。ファイルを1行ずつ読んでいて、最終出力を次のように印刷する必要があります--

Date=> 09/27/2009
Time=> 19:48:00 
Text=> Departure Location

次のように、1回のパスで置換を実行しようとしました-

if($line =~ m/(\d+)\/(\d+)\/(\d+)\h{1}(\d+):(\d+):(\d+)/){

    $line =~ s/(\[a-zA-Z])/\nText=> $1/;
    $line =~ s/(\d+)\/(\d+)\/(\d+)/\nDate=> $1\/$2\/$3/;
    $line =~ s/\h{1}(\d+):(\d+):(\d+)/\nTime=> $1\:$2\:$3/;

    print FH "$line\n";

}

しかし、私が得ているのはこれだけです-

Date=> 09/27/2009
Time=> 19:48:10 Departure Location

のマッチングに問題があることはわかっていますがText、修正できません。まだまだPerl初心者です。どんな助けでも大歓迎です。ありがとう!

4

4 に答える 4

5

ここでは、制限付きの分割がうまく機能します。これpairwiseは厳密には必要ありませんが、ループを回避するのに役立ちました:

#!/usr/bin/env perl

use strict; use warnings;
use feature 'say';
use List::MoreUtils qw( pairwise );

my $input = q{09/27/2009 19:48:00 Departure Location};
my @fields = qw(Date Time Text);
my @values = split ' ', $input, @fields;

{
    no warnings 'once';
    say join("\n", pairwise { "$a=> $b" } @fields, @values);
}

出力:

日付=> 2009/09/27
時間=> 19:48:00
テキスト=>出発地
于 2012-07-09T06:39:37.470 に答える
4

特にこのパターンはあなたに問題を引き起こしています:

$line =~ s/(\[a-zA-Z])/\nText=> $1/;

それにはいくつかの問題があります。まず、左角かっこの前のバックスラッシュ: \[は角かっこをエスケープしているため、文字クラスはまったく文字クラスではなく、リテラル テキスト " [a-zA-Z]" になります。第 2 に、テキスト マッチでは「空白」は許可されないため、文字列のテキスト部分にスペース文字 (または句読点) が含まれていると、マッチに失敗します。第 3 に、量指定子がないため、1 文字のみに一致します。最後の注意点は、おそらく文字列の最後に固定する必要があるということです。次のように動作する可能性があります (ただし、使用しないでください。代わりに読み進めてください)。

$line =~ s/([a-zA-Z\s]+)$/\nText=> $1/;

しかし、おそらくもっと良い解決策があります。明確さを失うことなく、すべてを 1 回のパスで実行できます。私には、より大きなセグメントをキャプチャすると、より意味があり始めます。

$string =~ s{^
    (\d\d/\d\d/\d{4})\s    # The date.
    (\d\d:\d\d:\d\d)\s     # The time.
    (.+)$                  # The rest (the text).
}{Date=> $1\nTime=> $2\nText=> $3}x;

通常の場合と同様に、/x 修飾子を使用すると、コードが読みやすくなります。

Perl の正規表現を理解するための優れたリソースがいくつかあります。perldoc perlretutから始めることをお勧めします。これは「Perl で正規表現を理解し、作成し、使用するための基本的なチュートリアル」です。

名前付きキャプチャを使用すると、特に正規表現がより複雑になるにつれて、ある程度の明確さを追加することもできます。

$string =~ s{
    ^
    (?<date>\d\d/\d\d/\d{4})\s
    (?<time>\d\d:\d\d:\d\d)\s
    (?<text>.+)
    $
}
{Date=> $+{date}\nTime=> $+{time}\nText=> $+{text}}x;
于 2012-07-09T04:40:47.373 に答える
2

小さなスペースに多くの機能を詰め込むことは、Perl が理解できないという評判に貢献するだけです。

このコードは私にははるかに明確に見えます

$line = <<END if $line =~ m|^(\d\d/\d\d/\d{4}) \s+ (\d\d:\d\d:\d\d) \s+ (.*)|x;
Date=> $1
Time=> $2 
Text=> $3
END
于 2012-07-09T16:01:45.300 に答える
2

パーサーであまりにも多くの作業を行っています。

my ($date, $time, $text) = split(' ', $_, 3);
say "Date=> $date";
say "Time=> $time";
say "Text=> $text";
于 2012-07-09T05:36:58.820 に答える