我有以下文件:
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
我希望找到所有日期(即2012年1月27日,2012年1月28日)并用今天的日期替换最新的日期(即2012年1月28日)。我希望用较旧的日期替换所有较旧的日期。我告诉你一个例子,因为我认为你最多可以理解我。假设今天是21.11.2012。我希望以2012年11月21日,2012年1月27日和2012年11月27日更新28.01.2012。如果有26.01.2012我想用19.11.2012替换它。
任何人都可以告诉我如何做到这一点?
也许有些暗示算法应该如何?我很想在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;
}
但这不是我想要的。
答案 0 :(得分: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
答案 1 :(得分:2)
CPAN上有一个批次的日期和时间模块。
您需要找到一个可以轻松添加N天的日期。使用POSIX模块中的mktime
和strftime
以及POSIX::strptime模块中的strptime
可能就足够了。
您需要通过指定要成为当前日期的“旧日期”来确定N.您计算两个日期(旧日期和当前日期)之间的差异,以天为单位,给出一个整数值N.然后为每个日期行提取日期部分,添加N天,并重写日期部分与新的假日期。
您询问确定“最早”的日期。您显示的格式基于ISO 8601,这意味着20120127等字符串可以按字符串或数字排序,以提供日期顺序。您似乎也有一个日志文件;在这样的文件中,第一个日期通常是最旧的,最后一个日期是最新的,因为它们是以单调递增的时间顺序顺序写入的。
答案 2 :(得分: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
答案 3 :(得分: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
。
要确定日期替换,您可以使用将{jilian day ordinal转换为day-month-year三元组的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);