-1

3つの可能な形式の日付を取得する必要があります。

  1. 2012/11/20
  2. 2012.11.20
  3. 2012 年 11 月 20 日

Perlでこれを達成するにはどうすればよいですか。私は欲しいものを得るために正規表現を試みています。これが私のコードです。

my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012"); #array values may vary in every run 
foreach my $date (@dates){
    $date =~ /[-.\/\d+]/g;
    print "Date: $date \n";
}

出力をしたい。(上記のコードは何も出力しません)

Date: 11/20/2012
Date: 2012.11.20
Date: 20-11-2012

どこが間違っていますか?助けてください。ありがとう

注: できるだけ CPAN モジュールを使用せずにこれを実現したいと考えています。私が望むものを提供できる CPAN モジュールがたくさんあることは知っています。

4

4 に答える 4

3

あなたのコードは、あなたが望むものをほとんど生成します。入力がもう少し複雑であるか、実際には実行していないコードを投稿したと思います。

いずれにせよ、問題はこれです

$date =~ /[-.\/\d+]/g;

まず、プラス乗数は文字クラス内にあります。それはその後にあるべきです。次に、これは単なるパターン マッチです。リスト コンテキストで使用し、戻り値を格納する必要があります。

my ($match) = $date =~ /[-.\/\d]+/g;
print "Date: $match\n";

次に、ダッシュ、ピリオド、スラッシュ、または数字を 1 つ以上含む最初の文字列が返されます。厳密でない正規表現であるため、他のものにも一致することに注意してください。

なぜそれが機能するのですか?/gグローバル修飾子が使用されている場合、リスト コンテキストでのパターン マッチは一致のリストを返すためです。

于 2013-03-05T08:07:55.490 に答える
2

フォーマットを1つずつ検索してみませんか?

=~ m!(\d{2}/\d{2}/\d{2}|\d{4}\.\d{2}\.\d{2}|\d{2}-\d{2}-\d{4})!

トリックを行う必要があります。それ以外に、DateTimeと呼ばれる日付を処理するモジュールがあります。

于 2013-03-05T07:36:45.307 に答える
2

豊富な機能を備えたDateTime::Format::Strptimeモジュールの使用を強くお勧めします。文字列を解析するだけでなく、日付が有効であることを確認することも考えてください。

于 2013-03-05T07:35:38.420 に答える
1

フォーマットを順番に一致させてみてください。以下の正規表現は、許可されているセパレーター(、、、または)のいずれかに一致し、/後方.参照(または)-を介して同じセパレーターを必要とします。それ以外の場合は、パターンに6つの選択肢を作成するために、3つの可能なセパレーターに1年の2つの可能な位置を掛けたものがあります。\2\3

#! /usr/bin/env perl

use strict;
use warnings;

#array values may vary in every run
my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012");

my $date_pattern = qr<
  \b  # begin on word boundary
  (
    (?:           [0-9][0-9] ([-/.]) [0-9][0-9] \2 [0-9][0-9][0-9][0-9])
  | (?: [0-9][0-9][0-9][0-9] ([-/.]) [0-9][0-9] \3 [0-9][0-9])
  )
  \b  # end on word boundary
>x;

foreach my $date (@dates) {
  if (my($match) = $date =~ /$date_pattern/) {
    print "Date: $match\n";
  }
}

出力:

日付:11/20/2012
日付:2012.11.20
日付:2012年11月20日

上記のコードを最初に試したとき\2、YYYY-MM-DDの代替案があったはず\3でしたが、一致しませんでした。括弧のカウントを省くために、バージョン5.10.0では名前付きキャプチャバッファが追加されました

  • 名前付きキャプチャバッファ

パターン内のキャプチャ括弧に名前を付け、キャプチャされたコンテンツを名前で参照できるようになりました。命名構文は(?<NAME>....)です。構文を使用して、名前付きバッファーへの逆参照を行うことができ\k<NAME>ます。コードでは、新しい魔法のハッシュが使用され、キャプチャバッファの内容%+%-アクセスできます。

この便利な機能を使用すると、上記のコードは次のようになります。

#! /usr/bin/env perl

use 5.10.0;  # named capture buffers

use strict;
use warnings;

#array values may vary in every run
my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012");

my $date_pattern = qr!
  \b  # begin on word boundary
  (?<date>
    (?:           [0-9][0-9] (?<sep>[-/.]) [0-9][0-9] \k{sep} [0-9][0-9][0-9][0-9])
  | (?: [0-9][0-9][0-9][0-9] (?<sep>[-/.]) [0-9][0-9] \k{sep} [0-9][0-9])
  )
  \b  # end on word boundary
!x;

foreach my $date (@dates) {
  if ($date =~ /$date_pattern/) {
    print "Date: $+{date}\n";
  }
}

同じ出力を生成します。

上記のコードにはまだ多くの繰り返しが含まれています。名前付きキャプチャと組み合わせた特殊なケースを使用(DEFINE)すると、パターンをより適切にすることができます。

#! /usr/bin/env perl

use 5.10.0;

use strict;
use warnings;

#array values may vary in every run
my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012");

my $date_pattern = qr!
  \b (?<date> (?&YMD) | (?&DMY)) \b

  (?(DEFINE)
    (?<SEP>  [-/.])
    (?<YYYY> [0-9][0-9][0-9][0-9])
    (?<MM>   [0-9][0-9])
    (?<DD>   [0-9][0-9])
    (?<YMD>  (?&YYYY) (?<sep>(?&SEP)) (?&MM) \k<sep> (?&DD))
    (?<DMY>  (?&DD)   (?<sep>(?&SEP)) (?&MM) \k<sep> (?&YYYY))
  )
!x;

foreach my $date (@dates) {
  if ($date =~ /$date_pattern/) {
    print "Date: $+{date}\n";
  }
}

はい、DMYという名前のサブパターンもMDY形式の日付と一致します。今のところそれで十分です、そしてあなたはそれを必要としないでしょう

于 2013-03-05T12:14:17.117 に答える