命令行上的正则表达式替换和重新排序

时间:2017-03-03 13:01:26

标签: regex perl sed

我必须遵循文字:

 30/01/2017 00:00:00                 158
 30/01/2017 00:30:00                 158
 30/01/2017 01:00:00                 158
 30/01/2017 01:30:00                 158
 30/01/2017 02:00:00                 158
 30/01/2017 02:30:00                 158
 30/01/2017 03:00:00                 158
 30/01/2017 03:30:00                 158
 30/01/2017 04:00:00                 158
 30/01/2017 04:30:00                 158
 30/01/2017 05:00:00                 158
 30/01/2017 05:30:00                 158
 30/01/2017 06:00:00                 158
 30/01/2017 06:30:00                 157
 30/01/2017 07:00:00                 157
 30/01/2017 07:30:00                 157
 30/01/2017 08:00:00                 157

我希望使用正则表达式以ISO格式重新排序日期并转换为.csv文件。

我对这些命令进行了测试:

perl -pe 's/(\s)([0-9]{2})\/([0-9]{2})\/([0-9]{4})\s([0-9]{2}:[0-9]{2}:[0-9]{2})(\s+)(.*)/$4-$3-$2_$5;$7;931;2/g' file.txt > output.csv

sed -E 's/(\s)([0-9]{2})\/([0-9]{2})\/([0-9]{4})\s([0-9]{2}:[0-9]{2}:[0-9]{2})(\s+)(.*)/\4-\3-\2_\5;\7;931;2/g' file.txt > output.csv

预期结果是:

2017-01-30_00:00:00;158;931;2
2017-01-30_00:30:00;158;931;2
2017-01-30_01:00:00;158;931;2
2017-01-30_01:30:00;158;931;2
2017-01-30_02:00:00;158;931;2
2017-01-30_02:30:00;158;931;2
2017-01-30_03:00:00;158;931;2
2017-01-30_03:30:00;158;931;2
2017-01-30_04:00:00;158;931;2
2017-01-30_04:30:00;158;931;2
2017-01-30_05:00:00;158;931;2
2017-01-30_05:30:00;158;931;2
2017-01-30_06:00:00;158;931;2
2017-01-30_06:30:00;157;931;2
2017-01-30_07:00:00;157;931;2
2017-01-30_07:30:00;157;931;2
2017-01-30_08:00:00;157;931;2

但结果是:

;931;21-30_00:00:00;158
;931;21-30_00:30:00;158
;931;21-30_01:00:00;158
;931;21-30_01:30:00;158
;931;21-30_02:00:00;158
;931;21-30_02:30:00;158
;931;21-30_03:00:00;158
;931;21-30_03:30:00;158
;931;21-30_04:00:00;158
;931;21-30_04:30:00;158
;931;21-30_05:00:00;158
;931;21-30_05:30:00;158
;931;21-30_06:00:00;158
;931;21-30_06:30:00;157
;931;21-30_07:00:00;157
;931;21-30_07:30:00;157
;931;21-30_08:00:00;157

注意** 931; 2 **在开头,但它是在最后。甚至吃了2017年的一部分。

为什么会这样?

2 个答案:

答案 0 :(得分:4)

问题几乎可以肯定是您使用Linux来处理源自Windows系统的文件,该文件具有CR LF行结尾。正则表达式模式末尾的.*与每行上最后一个数字(但不是LF)之后的CR匹配,因此将其保留在$7中并将其插入到输出中。这使;931;2出现在行的开头,覆盖之前的字符

解决此问题的一种方法是将chomp替换为s/\R\z//,它将匹配行尾的CR,LF或CR LF中的任何一个,因此处理任何行的结尾系统

你的正则表达式是正确的,但我只是收集每条记录中的所有数字字段,并使用printf重新格式化输出。这样就不需要删除在第一个地方结束的行

看起来像这样

use strict;
use warnings 'all';

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

while ( <$fh> ) {
    my @F = /\d+/ag;
    printf "%04d-%02d-%02d_%02d:%02d:%02d;%d;%d;%d\n",
            @F[2,1,0,3,4,5,6], 931, 2;
}

输出

2017-01-30_00:00:00;158;931;2
2017-01-30_00:30:00;158;931;2
2017-01-30_01:00:00;158;931;2
2017-01-30_01:30:00;158;931;2
2017-01-30_02:00:00;158;931;2
2017-01-30_02:30:00;158;931;2
2017-01-30_03:00:00;158;931;2
2017-01-30_03:30:00;158;931;2
2017-01-30_04:00:00;158;931;2
2017-01-30_04:30:00;158;931;2
2017-01-30_05:00:00;158;931;2
2017-01-30_05:30:00;158;931;2
2017-01-30_06:00:00;158;931;2
2017-01-30_06:30:00;157;931;2
2017-01-30_07:00:00;157;931;2
2017-01-30_07:30:00;157;931;2
2017-01-30_08:00:00;157;931;2

在单行中,

perl -ne '@F = /\d+/ag; printf "%04d-%02d-%02d_%02d:%02d:%02d;%d;%d;%d\n", @F[2,1,0,3,4,5,6], 931, 2;' myfile

答案 1 :(得分:0)

这可能适合你(GNU sed):

sed -r 's/^.(..).(..).(....).(........)\s*(\S*).*/\3-\2-\1_\4;\5;931;2/' file