3

私は次のファイルを持っています:

    20120127.221500.std|MT:63|ST:1.|ON:ABT.N|DRT:U|SEQ:862461707
      80 Bezahlt        : 55.04
      81 Bezahlt_Umsatz : 200
     281 Bezahlt_Zeit   : 22:00:02
     752 Quelle         : CTS OTC
      83 Umsatz_gesamt  : 5639295
     621 VWAP           : 54.984104
      26 Zeit           : 22:00:05

    20120127.232408.std|MT:63|ST:1.|ON:ABT.N|DRT:U|SEQ:862507497
      41 Schluss        : 55.02
     120 Schluss_Datum  : 27.01.2012

    20120128.011558.std|MT:63|ST:1.|ON:ABT.N|DRT:U|SEQ:862559511
      25 Datum          : 28.01.2012
      26 Zeit           : 01:01:30

すべての日付(つまり、27.01.2012、28.01.2012)を検索し、最新の日付(つまり、28.01.2012)を今日の日付に置き換えたいと思います。古い日付をすべて古い日付に置き換えたいのですが。私はあなたに例を示します、なぜならあなたは私をよく理解できると思うからです。今日が21.11.2012であると仮定しましょう。2012年1月28日を2012年11月21日に、2012年1月27日を2012年11月20日に置き換えたいと思います。2012年1月26日があった場合は、2012年11月19日に置き換えたいと思います。

誰でも私に手がかりを与えることができますか?

たぶん、アルゴリズムがどのように見えるべきかについてのいくつかのヒントはありますか?私はperlでそれをやりたいです。

私の問題は、どのようにして最も古い日付を特定できるかということです。私は次のようなものから始めました:

  open F ,"<$file";
    my $content = do{local $/;<F> };
    if ($content =~ /BOERSEN : [N|Q]/)
    {
      $content =~ /(\d\d\.\d\d\.\d\d\d\d)/;
      my $d = $1;
      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
      $year+= 1900;
      $mon +=1;
      $mon = sprintf("%02d", $mon);
      $content =~ s/(\d\d)\.\d\d\.\d\d\d\d/$1\.$mon\.$year/msgi;
      my @d = split (/\./, $d);
      $d = $d[2].$d[1];
      $content =~ s/$d(\d\d)/$year$mon$1/msgi;
    }

しかし、それは私が本当に望んでいることではありません。

4

4 に答える 4

3

私は少し浮気してこれを思いついた。最初に完全な入力を読み取る必要がありますが、その後は機能します。

#!/usr/bin/perl
use strict; use warnings;
use DateTime;
use DateTime::Format::Strptime;

my $text = <<'TEXT';
foo 27.01.2012 27-01-2012
foo 28.01.2012 28-01-2012
foo 26.01.2012 26-01-2012
bar 10.07.2011 10-07-2011
TEXT

# Formatter to make DateTime objects
my $strp = DateTime::Format::Strptime->new(
    pattern   => '%d.%m.%Y',
);
my $today = DateTime->today; # we need that to calculate

# Get all the dates from the input and turn them into DateTime objects
my %dates = map { $_ => $strp->parse_datetime($_) }
    $text =~ m/(\d{2}\.\d{2}.\d{4})/gm;

# Determine the latest date (the one nearest to today) and clone it
my $max_date = (sort { DateTime->compare( @dates{$a, $b} ) } keys %dates )[-1];
$max_date = $dates{$max_date}->clone;

foreach my $date ( keys %dates ) {
    # The new value needs to have the same "distance" to today as the old one
    # had to the highest date from the input

    # Do that calculation and format it
    my $new_date = $strp->format_datetime(
        $today - ($max_date - $dates{$date}));
    # Needs \Q and \E because there are '.' in the date
    $text =~ s/\Q$date\E/$new_date/g;
}

出力は次のとおりです。

foo 22.11.2012 27-01-2012
foo 23.11.2012 28-01-2012
foo 21.11.2012 26-01-2012
bar 05.05.2012 10-07-2011
于 2012-11-23T17:01:12.143 に答える
2

CPANには多くの日付と時刻のモジュールがあります。

日付にN日を簡単に追加できるものを見つける必要があります。POSIXモジュールおよびmktimePOSIX ::strptimeモジュールを使用strftimeするだけで十分な場合があります。strptime

現在の日付にしたい「古い日付」を指定して、Nを決定する必要があります。2つの日付(古い日付と現在の日付)の差を日数で計算し、整数値Nを求めます。次に、各日付行について、日付部分を抽出し、それにN日を追加して、日付部分を書き換えます。新しい偽の日付で。


あなたは「最も古い」日付を決定することについて尋ねます。表示する形式はISO8601に基づいています。つまり、20120127などの文字列は、文字列または数値として並べ替えて、日付の順序を指定できます。また、ログファイルがあるようです。このようなファイルでは、通常、最初の日付が最も古く、最後の日付が最も新しくなります。これは、単調に増加する時間順に順番に書き込まれるためです。

于 2012-11-23T16:27:31.243 に答える
2

このTime::Pieceモジュールはこの目的には十分であり、コアモジュールであるため、インストールする必要はありません。

このプログラムは、現在の日付と時刻を取得し、%d.%m.%Y文字列としてフォーマットして読み戻すことにより、時刻フィールドをゼロに設定します。次に、ログファイルを開いて読み取り、すべての日付を調べて最新の日付を見つけます。ファイル内の最新の日付と現在の日付の間のデルタが計算され、ファイルは最初に巻き戻されて再度読み取られます。今回は、すべての日付に計算されたデルタが追加され、文字列が出力で置き換えられます。

use strict;
use warnings;

use Time::Piece ();
use Fcntl ':seek';

my $today = Time::Piece->new;
$today = Time::Piece->strptime($today->dmy('.'), '%d.%m.%Y');

open my $fh, '<', 'logfile.txt' or die $!;

my $latest = 0;

while (<$fh>) {
  if ( /:\s*(\d\d\.\d\d\.\d\d\d\d)/ ) {
    my $date = Time::Piece->strptime($1, '%d.%m.%Y');
    $latest = $date if $date > $latest;
  }
}

my $delta = $today - $latest;
seek $fh, 0, SEEK_SET;

while (<$fh>) {

  s{:\s*\K(\d\d\.\d\d\.\d\d\d\d)}{
    my $date = Time::Piece->strptime($1, '%d.%m.%Y');
    $date += $delta;
    $date->dmy('.');
  }eg;

  print;
}

出力

20120127.221500.std|MT:63|ST:1.|ON:ABT.N|DRT:U|SEQ:862461707
  80 Bezahlt        : 55.04
  81 Bezahlt_Umsatz : 200
 281 Bezahlt_Zeit   : 22:00:02
 752 Quelle         : CTS OTC
  83 Umsatz_gesamt  : 5639295
 621 VWAP           : 54.984104
  26 Zeit           : 22:00:05

20120127.232408.std|MT:63|ST:1.|ON:ABT.N|DRT:U|SEQ:862507497
  41 Schluss        : 55.02
 120 Schluss_Datum  : 22.11.2012

20120128.011558.std|MT:63|ST:1.|ON:ABT.N|DRT:U|SEQ:862559511
  25 Datum          : 23.11.2012
  26 Zeit           : 01:01:30
于 2012-11-23T22:24:34.930 に答える
1

ファイルを操作するためのいくつかのポインタを次に示します。

open F ,"<$file";
my $content = do{local $/;<F> };
close(F);

my $DATE_RE = qr/((\dd)\.(\d\d)\.(\d\d\d\d))/;
my %jdate;
# Find all of the dates and convert them to date ordinals
while ($content =~ m/$DATE_RE/g) {
  $jdate{$1} ||= jdate($2, $3, $4);
}

# find the most recent date
my $latest;
for my $d (keys %jdate) {
  if (!$latest || $jdate{$latest} < $jdate{$d}) {
    $latest = $d
  }
}

# for each date $d, determine what to replace it with
my %replacement;
for my $d (keys %jdate) {
  $replacement{$d} = ...your code here...
}

# Replace all of the dates
$content =~ s/$DATE_RE/$replacement{$1}/ge;

# done!

jdate(...)重要なのは、日-月-年を整数に変換する関数です。これを行うことができるCPANにはたくさんのモジュールがあります-例えばTime::JulianDay

日付の置換を決定するには、ユリウス日序数を日-月-年のトリプルに変換する関数を使用できますinverse_julian_day()。つまり、次のようになります。

my ($y, $m, $d) = inverse_julian_day( $today_jd - ($jdate{$latest} - $jdate{$d}) );
$replacement{$d} = sprintf("%02d.%02d.%04", $d, $m, $y);
于 2012-11-23T17:11:06.510 に答える