[英]extract specific data from log file line with regex then compare with timestamp from other lines and generate csv file
我是Perl的新手,将数据合并到一个新文件时遇到了问题。
我有一个日志文件(下面的示例),包括带有(RSSI值和时间戳)的行和带有(GPS位置(纬度,经度)和时间戳)的行。 GPS位置比RSSI值触发的频率更高,因此日志文件包含GPS位置的行多于具有RSSI值的行。
我必须找到与每个RSSI时间戳匹配的正确时间戳的GPS线。
时间戳具有99:99:99.999
格式。 要比较时间戳,我只需要99:99:99
格式。
最后,我想生成一个带有99:99:99格式的时间戳,RSSI值和相应GPS位置的新CSV文件,并丢弃无用的GPS位置。 CSV文件应包含(时间戳,RSSI,纬度,经度)。 日志文件如下所示。 (在此示例中,GPS位置不变,但实际上会改变。)
# .log file
# first rssi timestamp is 10:23:05.746 (hour:minute:second.microsecond) and RSSI value -91
Line 167: 0.11036 0 25.11.2014 10:23:05.746 01.01.1970 00:53:55.545 CON.NAD.CINTERION nadProc.NAD_Run_AT_Cmds info 55 NADCinterion::handleSMONI(3441): SMONI LTE_RSSI -91 -91
Line 1747: 0.12577 0 25.11.2014 10:23:07.967 01.01.1970 00:53:57.766 CON.NAD.CINTERION nadProc.NAD_Run_AT_Cmds info 55 NADCinterion::handleSMONI(3441): SMONI LTE_RSSI -92 -92
Line 2096: 0.12925 0 25.11.2014 10:23:11.744 01.01.1970 00:54:01.544 CON.NAD.CINTERION nadProc.NAD_Run_AT_Cmds info 55 NADCinterion::handleSMONI(3441): SMONI LTE_RSSI -93 -93
Line 3472: 0.14272 0 25.11.2014 10:23:15.745 01.01.1970 00:54:05.545 CON.NAD.CINTERION nadProc.NAD_Run_AT_Cmds info 55 NADCinterion::handleSMONI(3441): SMONI LTE_RSSI -92 -92
Line 4915: 0.15681 0 25.11.2014 10:23:17.965 01.01.1970 00:54:07.766 CON.NAD.CINTERION nadProc.NAD_Run_AT_Cmds info 55 NADCinterion::handleSMONI(3441): SMONI LTE_RSSI -94 -94
# first GPS timestamp is 10:23:05.716 (hour:minute:second.microsecond) and GPS position 11.38172906823456,48.78751751035452
Line 194: 0.11062 0 25.11.2014 10:23:05.716 01.01.1970 00:53:55.515 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
Line 819: 0.11672 0 25.11.2014 10:23:06.715 01.01.1970 00:53:56.514 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
Line 1443: 0.12281 0 25.11.2014 10:23:07.716 01.01.1970 00:53:57.515 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
Line 2538: 0.13558 0 25.11.2014 10:23:08.714 01.01.1970 00:54:04.514 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
Line 2738: 0.13558 0 25.11.2014 10:23:11.714 01.01.1970 00:54:04.514 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
Line 3324: 0.14130 0 25.11.2014 10:23:15.714 01.01.1970 00:54:05.514 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
Line 4261: 0.15048 0 25.11.2014 10:23:17.114 01.01.1970 00:54:06.914 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
Line 4694: 0.15466 0 25.11.2014 10:23:17.813 01.01.1970 00:54:07.614 BL.POSITIONING navi.DEF_THR debug 98 PositionNLAdapter < pos:11.38172906823456,48.78751751035452 heading: 156.0113220214844 speed:0km/h
我必须使用LTE_RSSI $line =~ /RSSI/
获得正确的行,然后从该行$lines_rssi
获得时间戳记$rssi_timestamp
和RSSI值$lte_rssi
并使用正则表达式m/(\\-\\d+$)/
。
获取具有GPS位置和时间戳记的右行BL.POSITIONING $line =~ m/BL.POSITIONING/
,然后从该行$lines_gps
获得时间戳记$gps_timestamp
以及对应的GPS位置$latitude
和$longitude
并使用正则表达式m/pos:(\\d+\\.\\d+),(\\d+\\.\\d+)/
。
将时间戳记从99:99:99.999
99:99:99
为99:99:99
进行比较。
从RSSI线中获取第一个修改后的时间戳,并将其与GPS线中的修改后的时间戳进行比较,并且在匹配时间戳时,从该行中获取该GPS位置。
打印出具有修改后的RSSI时间戳,RSSI值,来自匹配GPS线的GPS位置的CSV文件(请参见第4点)。
我的代码如下所示。 它打印出所有RSSI时间戳和值以及所有GPS时间戳和位置,但不会相互比较这些时间戳。 然后仅打印一个时间戳,RSSI值,纬度,经度
#!/usr/bin/perl
use strict;
use warnings;
print "Geben Sie den Namen der log Datei ein: " ;
my $log =<STDIN>;
open(LOG, $log) || die "Log nicht gefunden";
my $rssi_timestamp; #rssi timestamp in format dd:dd:dd.ddd
my $lte_rssi; #rssi value
my $gps_timestamp; #gps timestamp ind format dd:dd:dd.ddd
my $latitude; #gps latitude
my $longitude; #gps longitude
my $lines_rssi; #one complete line with rssi
my $lines_gps; #one complete line with gps
my $gps_timestamp_mod; #modified gps timestamp in format dd:dd:dd
my $rssi_timestamp_mod; #modified rssi timestamp in format dd:dd:dd
while (my $line = <LOG>)
{
if ($line =~ /RSSI/) #find right line containing rssi value (regex RSSI)
{
$lines_rssi = $line;
$lines_rssi =~ m/(\d{2}\:\d{2}\:\d{2}\.\d{3})/; #find matching timestamp pattern with regex
$rssi_timestamp = $1;
print "$rssi_timestamp,";
$rssi_timestamp =~ m/(\d{2}\:\d{2}\:\d{2})/; #modify rssi timestamp format from dd:dd:dd.ddd to dd:dd:dd
$rssi_timestamp_mod = $1;
print "$rssi_timestamp_mod,";
$lines_rssi =~ m/(\-\d+$)/; #find rssi value with regex
$lte_rssi = $1;
print "$lte_rssi\n";
}
if ($line =~ m/BL.POSITIONING/) #find line with GPS position with regex
{
$lines_gps = $line;
$lines_gps =~ m/(\d{2}\:\d{2}\:\d{2}\.\d{3})/; # find matching timestamp in gps line
$gps_timestamp = $1;
$gps_timestamp =~ m/(\d{2}\:\d{2}\:\d{2})/;
$gps_timestamp_mod = $1;
if ($gps_timestamp_mod == $rssi_timestamp_mod) # here i want to compare the 2 modified timestamps with each other to find the right gps line but it doesn't work
{
$lines_gps =~ m/pos:(\d+\.\d+),(\d+\.\d+)/;
$latitude = $2;
$longitude = $1;
print "$gps_timestamp,$gps_timestamp_mod,$latitude,$longitude\n";
}
}
}
CSV文件应类似于(时间戳,rssi,纬度,经度)。
仅来自RSSI值的时间戳记应在此处(10:23:05、10:23:07、10:23:11、10:23:15、10:23:17)丢弃带有(10: 23:06、10:23:08和10:23:17之一):
10:23:05,-91,48.78751751035452,11.38172906823456
10:23:07,-92,48.78751751035452,11.38172906823456
10:23:11,-93,48.78751751035452,11.38172906823456
10:23:15,-92,48.78751751035452,11.38172906823456
10:23:17,-94,48.78751751035452,11.38172906823456
有人可以帮我解决这个问题吗?
@Borodin:非常感谢您提供的代码。 它完美! 此外,就像您提到的那样,我也正在考虑GPS坐标的插值,如本文档中第2页上的公式(1)和(2)所述,GPS卫星坐标的多项式插值
代码中的插值有多复杂?
我认为这可以满足您的需求。 我没有删除小数秒,而是编写了一个子例程epoch_seconds
,该子例程使用Time::Piece
模块将时间(包括毫秒) 和日期转换为自1970年初以来的浮点秒。这将避免与之相关的任何问题。午夜左右的时间。
读取整个文件,并将相关数据存储在两个哈希中: %rssi
和%gps
,由浮点时间戳索引。 然后,通过使用List::UtilsBy
的min_by
函数找到时间戳上绝对差最小的元素,将%rssi
每个元素与%gps
元素配对。 然后只需要在找到的两个元素中打印所有数据。
您可能必须安装List::UtilsBy
因为它不是核心模块。
请注意,输出中实际报告的时间戳是$report_time
设置的值。 我删除了日期和小数秒,使其与您的示例相同,但是您可以根据需要进行修改。
在我看来,如果可以的话,在RSSI数据的任一侧的GPS坐标之间进行线性插值以获取更好的精度会很简单。
我希望这有帮助。
use strict;
use warnings;
use Time::Piece;
use List::UtilsBy qw/ min_by /;
print "Geben Sie den Namen der log Datei ein: ";
chomp(my $log_file = <STDIN>);
open my $log_fh, '<', $log_file or die "Log nicht gefunden: $!";
my $out_file = 'logfile.csv';
my (%rssi, %gps);
while (<$log_fh>) {
next if /^#/;
if (/LTE_RSSI/) { # find right line containing rssi value (regex RSSI)
next unless /( \d+\.\d+\.\d+ \s+ \d+:\d+:\d+\.\d+ )/x;
my $timestamp = $1;
my $timestamp_seconds = epoch_seconds($timestamp);
my ($report_time) = $timestamp =~ /(\d+:\d+:\d+)/;
next unless /(\-\d+$)/; # find RSSI value with regex
$rssi{$timestamp_seconds} = [$report_time, $1];
}
elsif (/BL\.POSITIONING/) { # find line with GPS position with regex
next unless /( \d+\.\d+\.\d+ \s+ \d+:\d+:\d+\.\d+ )/x;
my $timestamp = $1;
my $timestamp_seconds = epoch_seconds($timestamp);
next unless /pos:(\d+\.\d+),(\d+\.\d+)/;
$gps{$timestamp_seconds} = [$2,$1];
}
}
open my $out_fh, '>', $out_file or die qq{Unable to open "$out_file" for output: $!};
for my $rssi_seconds (sort { $a <=> $b } keys %rssi) {
my $gps_seconds = min_by { abs($_ - $rssi_seconds) } keys %gps;
print $out_fh join(',', @{ $rssi{$rssi_seconds} }, @{ $gps{$gps_seconds} }), "\n";
}
sub epoch_seconds {
my ($date_time) = @_;
die unless shift =~ /(.+)\.(.+)/;
Time::Piece->strptime($1, '%d.%m.%Y %H:%M:%S')->epoch . ".$2";
}
产量
10:23:05,-91,48.78751751035452,11.38172906823456
10:23:07,-92,48.78751751035452,11.38172906823456
10:23:11,-93,48.78751751035452,11.38172906823456
10:23:15,-92,48.78751751035452,11.38172906823456
10:23:17,-94,48.78751751035452,11.38172906823456
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.