繁体   English   中英

使用正则表达式从日志文件行中提取特定数据,然后与其他行中的时间戳进行比较并生成CSV文件

[英]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
  1. 我必须使用LTE_RSSI $line =~ /RSSI/获得正确的行,然后从该行$lines_rssi获得时间戳记$rssi_timestamp和RSSI值$lte_rssi并使用正则表达式m/(\\-\\d+$)/

  2. 获取具有GPS位置和时间戳记的右行BL.POSITIONING $line =~ m/BL.POSITIONING/ ,然后从该行$lines_gps获得时间戳记$gps_timestamp以及对应的GPS位置$latitude$longitude并使用正则表达式m/pos:(\\d+\\.\\d+),(\\d+\\.\\d+)/

  3. 将时间戳记从99:99:99.999 99:99:9999:99:99进行比较。

  4. 从RSSI线中获取第一个修改后的时间戳,并将其与GPS线中的修改后的时间戳进行比较,并且在匹配时间戳时,从该行中获取该GPS位置。

  5. 打印出具有修改后的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::UtilsBymin_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM