Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 使用正则表达式从日志文件行提取特定数据,然后与其他行的时间戳进行比较,生成csv文件_Regex_Perl_Csv_Scripting_Timestamp - Fatal编程技术网

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

Regex 使用正则表达式从日志文件行提取特定数据,然后与其他行的时间戳进行比较,生成csv文件,regex,perl,csv,scripting,timestamp,Regex,Perl,Csv,Scripting,Timestamp,我是Perl新手,在将数据合并到新文件时遇到问题 我有一个日志文件(下面的例子),包括带有(RSSI值和时间戳)的行和带有(GPS位置(纬度、经度)和时间戳)的行。触发GPS位置的频率高于RSSI值,因此日志文件包含的GPS位置线多于RSSI值线 我必须找到与每个RSSI时间戳匹配的正确时间戳的GPS线 时间戳的格式为99:99:99.999。要比较时间戳,我只需要99:99:99格式 最后,我想生成一个新的CSV文件,其中包含99:99:99格式的时间戳、RSSI值和相应的GPS位置,丢弃无用

我是Perl新手,在将数据合并到新文件时遇到问题

我有一个日志文件(下面的例子),包括带有(RSSI值和时间戳)的行和带有(GPS位置(纬度、经度)和时间戳)的行。触发GPS位置的频率高于RSSI值,因此日志文件包含的GPS位置线多于RSSI值线

我必须找到与每个RSSI时间戳匹配的正确时间戳的GPS线

时间戳的格式为
99:99:99.999
。要比较时间戳,我只需要
99:99:99
格式

最后,我想生成一个新的CSV文件,其中包含99:99:99格式的时间戳、RSSI值和相应的GPS位置,丢弃无用的GPS位置。CSV文件应包含(时间戳、RSSI、纬度、经度)。日志文件如下所示。(在本例中,GPS位置不会改变,但实际上会改变。)

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之一)的GPS测线:

有人能帮我解决这个问题吗

@博罗丁:非常感谢你的密码。它工作完美! 此外,正如你提到的,我也在考虑GPS坐标的插值,就像在第2页的公式(1)和(2)中解释的一样


代码中的插值有多复杂?

我想这正是你想要的。我没有删除小数秒,而是编写了一个子程序
epoch\u seconds
,它使用模块将时间(包括毫秒)和日期转换为1970年初以来的浮点秒。这样可以避免午夜前后的时间问题

读取整个文件,并将相关数据存储在两个散列中:
%rssi
%gps
,由浮点时间戳索引。然后,通过使用来自的
min_by
函数查找时间戳绝对差最小的元素,将
%rssi
的每个元素与
%gps
的元素配对。然后,只需打印找到的两个元素中的所有数据

您可能必须安装
List::UtilsBy
,因为它不是核心模块

请注意,输出中实际报告的时间戳是
$report\u 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";
}

好吧,我明白了。因此,您的程序会打印所有输入记录中的相关字段,但您不确定如何将每个RSSI记录与相关GPS记录联系起来?您希望如何确定匹配的GPS记录?是时间最近的那个,还是时间晚的第一个,还是别的什么?RSSI记录和GPS记录是否在同一个文件中?文件可能有多大?另外,请说明您使用的是什么版本的Perl?最好是通过编辑帖子而不是评论来回答这些问题。谢谢。嗨,博罗丁,非常感谢!代码完全符合我的要求。甚至将GPS记录与最接近时间的RSSI记录进行匹配。GPS坐标之间的插值会很好。我也在想这个。你认为这会很简单吗?我正在考虑使用本文中使用的多项式函数(见我的原始帖子末尾)。
#!/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";
    }
  }
}
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
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