sed - 更改具有特定位数的模式

时间:2016-08-18 08:51:41

标签: regex perl

我试图在以下一组行上进行替换:

1AA20160817BBBBBDIGITS1NUMBER1STYLE59        00002200000220
1AA20160817BBBBBDIGITS2NUMBER1STYLE60        00000000000220
1AA20160817DDDDDDIGITS3NUMBER2STYLE60        00000000000486
1AA20160817DDDDDDIGITS4NUMBER2STYLE59        00004860000486
1AA20160817FFFFFDIGITS5NUMBER3STYLE602523111100000000000000
1AA20160817FFFFFDIGITS6NUMBER3STYLE59        00000820000000

我希望最终输出如下:

1AA20160817BBBBBDIGITS1NUMBER1STYLE59        00002200000220
1AA20160817BBBBBDIGITS1NUMBER1STYLE60        00000000000220
1AA20160817DDDDDDIGITS3NUMBER2STYLE60        00000000000486
1AA20160817DDDDDDIGITS3NUMBER2STYLE59        00004860000486
1AA20160817FFFFFDIGITS5NUMBER3STYLE602523111100000000000000
1AA20160817FFFFFDIGITS5NUMBER3STYLE59        00000820000000

更改是一位数,就在每秒的“数字”之前。 BBBBB / DDDDD样式的模式是时间,最后一个字符是秒指示符。

我希望它检查特定数量的字符并在那里执行更改,我写了sed来执行该任务及其类似:

sed -i.bak "s/^\(.\{1\}\)$scenario$datein\(.\{6\}\)$pod/1$scenario$datein$timein$pod/g" $1

其余代码在Perl中。你们中的一个可以帮我在Perl中做同样的替换吗?或者也许告诉我如何运行这个sed命令,从perl代码?我的问题是有问题的文件是巨大的,并且bash需要很长时间才能读取每一行,并执行替换。提前谢谢。

2 个答案:

答案 0 :(得分:2)

假设您的输入数据位于data.txt

$ perl -i -pe's/(\d)(?=NUMBER)/$1-1/e if ! ($. % 2)' data.txt
  • -i:就地编辑输入文件并创建备份
  • -p:在输入的每一行运行此代码并在每次迭代时打印$ _
  • -e:要运行的代码
  • s/(\d)(?=NUMBER)/$1-1/e:找一个数字后跟“' NUMBER'并将其替换为从数字
  • 中减去的一个
  • if ! ($. % 2):但只对偶数编号记录执行此操作

答案 1 :(得分:0)

更新已清除substr上的语句,这些语句指的是“号码”,考虑到发布的数据 - substr有效用字符串。用更好的方法替换魔法22以找到偏移量。

您可以通过查看$. - 从(上次访问的)文件句柄读取的当前行号来识别偶数行和奇数行。见in perlvar

use warnings;
use strict;

my $set_num_to = 0;

while (<DATA>) 
{
    if ($. % 2 != 0) { # odd line number
        ($set_num_to) = $_ =~ m/(\d)NUMBER/;
        print;
    }
    else { 
        s/\d(?=NUMBER)/$set_num_to/;
        print;
    }
}

__DATA__
1AA20160817BBBBBDIGITS1NUMBER1STYLE59        00002200000220
1AA20160817BBBBBDIGITS2NUMBER1STYLE60        00000000000220
1AA20160817DDDDDDIGITS3NUMBER2STYLE60        00000000000486
1AA20160817DDDDDDIGITS4NUMBER2STYLE59        00004860000486
1AA20160817FFFFFDIGITS5NUMBER3STYLE602523111100000000000000
1AA20160817FFFFFDIGITS6NUMBER3STYLE59        00000820000000

正则表达式使用字符串NUMBER,如示例中所示,并且缺少更多细节,以识别要在奇数行上获取的数字,然后用于替换偶数位置上的数字线。它使用positive lookahead(?=PATTERN)。如果替换应该比当前数字少一个(而不是前一行的数字),你可以使用

s/(\d)(?=NUMBER)/$1-1/e if $. % 2 == 0;

/e修饰符首先评估替换方,然后将其结果用作替换方。请参阅perlopthis post

如果位置固定,可以使用substr

my $offset = length '1AA20160817BBBBBDIGITS';

while (<DATA>) 
{
    if ($. % 2 != 0) {
        # Retrieve substring of length 1 at given offset
        $set_num_to = substr $_, $offset, 1;
    }
    else {
        # Replace substring of same length at same offset by one captured above
        substr $_, $offset, 1, $set_num_to;
    }
}

其余部分相同,并按指定打印行。

同样,如果你需要从那里减去1而不是用前一行中的数字替换它,你可以在$. % 2 == 0条件下使用上面的两行。