【问题标题】:sed, replace globally a delimiter with the first part of the linesed,用该行的第一部分全局替换分隔符
【发布时间】:2011-07-04 09:27:36
【问题描述】:

假设我有以下几行:

1:a:b:c 2:d:e:f 3:a:b 4:a:b:c:d:e:f

如何使用 sed(或 perl)编辑它以便阅读:

1a1b1c 2d2e2f 3a3b 4a4b4c4d4e4f

我已经完成了这样的 awk:

awk -F':''{gsub(/:/, $1, $0);打印 $0}'

但需要很长时间才能完成!所以寻找更快的东西。

【问题讨论】:

  • 您是想在脚本中执行此操作,还是只是一次性完成?

标签: perl sed


【解决方案1】:

'这有点棘手,但可以使用 sed 完成(假设文件 data 包含示例输入):

$ sed '/^\(.\):/{
s//\1/
: retry
s/^\(.\)\([^:]*\):/\1\2\1/
t retry
}' data
1a1b1c
2d2e2f
3a3b
4a4b4c4d4e4f
$

您可以用分号将脚本扁平化为一行; MacOS X 上的sed 有时有点胡思乱想并且反对某些部分,因此将其拆分为 6 行。第一行匹配以单个字符和冒号开头的行,并在识别时开始一系列操作。例如,第一个替代项仅将“1:”替换为“1”。 : retry 也是分支的标签——这是其中的关键部分。下一个替换将行上的第一个字符复制到第一个冒号上。如果替代品改变了任何东西,t retry 将返回标签。最后一行为最初匹配的行划定了整个操作序列。

【讨论】:

  • 太棒了,正是我想要的。谢谢!
【解决方案2】:
#!/usr/bin/perl
use warnings;
use strict;

while (<DATA>) {
    if ( s/^([^:]+)// ) {
        my $delim = $1;
        s/:/$delim/g;
    }
    print;
}

__DATA__
1:a:b:c
2:d:e:f
3:a:b
4:a:b:c:d:e:f

【讨论】:

    【解决方案3】:
    use feature qw/ say /;
    use strict;
    use warnings;
    while( <DATA> ) {
        chomp;
        my @elements = split /:/;
        my $interject = shift @elements;
        local $" = $interject;
        say $interject, "@elements";
    }
    
    __DATA__
    1:a:b:c
    2:d:e:f
    3:a:b
    4:a:b:c:d:e:f
    

    或者在 linux shell 命令行上:

    perl -aF/:/ -pe '$i=shift @F;$_=$i.join $i,@F;' infile.txt

    【讨论】:

    • 出于好奇,哪些版本的 Perl 支持use feature qq/ say /;
    • 据我所知,5.10 及更高版本。否则,就用print $interject, "@elements\n";说真的只是省了几下击键的快捷方式。除此之外没有什么特别之处。
    • 我应该补充一点,我使用&lt;DATA&gt;__DATA__ 作为在工作示例中包含输入数据的快捷方式。如果您正在从命令行上指定的文件中读取数据,并且正在调用 Perl 脚本(与 Perl 单行程序相反),您可以将 &lt;DATA&gt; 更改为 &lt;&gt; 并省略 __DATA__ 段。但你可能已经想通了。 ;)
    猜你喜欢
    • 2016-12-22
    • 2010-11-07
    • 1970-01-01
    • 2014-05-31
    • 2021-10-25
    • 2018-12-21
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    相关资源
    最近更新 更多