【问题标题】:sed - Changing pattern with specific number of digitssed - 使用特定位数更改模式
【发布时间】:2016-08-18 08:51:40
【问题描述】:

我正在尝试对以下行进行替换:

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 中做同样的替换吗?或者也许告诉我如何从 perl 代码运行这个 sed 命令?我的问题是有问题的文件很大,而 bash 读取每一行并执行替换需要很长时间。提前致谢。

【问题讨论】:

  • 第一个块和第二个块有什么区别?在我看来,它们看起来一样
  • 哦,很好,不只是我...... :)
  • 每隔一个块有 1 个不同的字符,就在“数字”之前
  • 将其添加到正文中,以免混淆。
  • 提供易于追踪的minimal reproducible example 总是好的。在这里,....CNUMBER......BNUMBER... 看起来非常相似。能不能把例子简化一下,让大家更容易回答,基本理解你的最终目标?

标签: regex perl


【解决方案1】:

假设你的输入数据在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): 但只对偶数记录这样做

【讨论】:

    【解决方案2】:

    通过查看$. 可以识别偶数行和奇数行——从(最后访问的)文件句柄中读取的当前行号。见in perlvar

    use warnings;
    use strict;
    
    my $set_num_to = 0;
    
    while (<DATA>) 
    {
        if ($. % 2 != 0) { # odd line number
            ($set_num_to) = /(\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 条件中使用上面的两行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-04
      • 1970-01-01
      • 2017-08-05
      • 2017-09-18
      • 2021-04-26
      • 2017-12-22
      相关资源
      最近更新 更多