3

有谁知道任何 unix 命令/perl 脚本会在特定字符的第 n 个重复出现的位置插入特定字符(可以输入为十六进制(即 7C)或实际字符(即 |))。即perl script.pl "," 3 "|" data.txt 会用管道替换每个第 3、6、9... 等逗号。

因此,如果 data.txt 在脚本运行之前具有以下内容:

fd,3232,gfd67gf,
peas,989767,jkdfnfgjhf,
dhdhjsk,267,ujfdsy,fuyds,637296,ldosi,fduy,
873,fuisouyd,try
save,2837,ipoi

在脚本运行后它应该有这个:

fd,3232,gfd67gf|
peas,989767,jkdfnfgjhf|
dhdhjsk,267,ujfdsy|fuyds,637296,ldosi|fduy,
873,fuisouyd|try
save,2837,ipoi
4

6 回答 6

5

小 perl hack 来解决这个问题。使用index函数查找逗号、模数替换正确的一个,并substr执行替换。

use strict;
use warnings;

while (<>) {
    my $x=index($_,","); 
    my $i = 0; 
    while ($x != -1) {
        $i++; 
        unless ($i % 3) { 
            $_ = substr($_,0,$x) ."|". substr($_,$x+1); 
        }
        $x = index($_,",",$x + 1) 
    } 
    print;
}

运行perl script.pl file.csv

注意:您可以将声明my $i放在while(<>)循环之前以便进行全局计数,而不是对每一行单独计数。不太确定我是否理解你在这方面的问题。

于 2012-04-14T12:36:10.967 回答
3

一个漂亮、简单awk的单线怎么样?

awk -v RS=, '{ORS=(++i%3?",":"|");print}' file.csv

我刚刚想到一个小错误:它会打印一个,|作为最后一个字符。为了避免这种情况,我们需要稍微改变一下:

awk -v RS=, '{ORS=(++i%3?",":"|");print}END{print ""}' file.csv | sed '$d'
于 2012-04-14T15:16:43.543 回答
3
use File::Slurp qw(read_file);
my ($from, $to, $every, $fname) = @ARGV;
my $counter = 0;
my $in = read_file $fname;
my $out = $in;
# copy is important because pos magic attached to $in resets with substr
while ($in =~ /\Q$from/gms) {
    $counter++;
    substr $out, pos($in)-1, length($from), $to unless $counter % $every;
};
print $out;

如果$from$to参数的长度不同,您仍然需要稍微弄乱第二个参数substr以使其正常工作。

于 2012-04-14T12:39:40.950 回答
1

这一次处理一行输入文件(没有 slurping :)
对于十六进制输入,只需传递'\x7C'或其他任何内容,如$1

#!/bin/bash  

b="${1:-,}"                             # the "before" field delimiter 
n="${2:-3}"                             # the number of fields in a group
a="${3:-|}"; [[ $a == [\|] ]] && a='\|' # the "after" group delimiter

sed -nr "x;G; /(([^$b]+$b){$((n-1))}[^$b]+)$b/{s//\1$a/g}
         s/.*\n//; h; /.*$a/{s///; x}; p" input_file

又来了,有一些评论。

sed -nr "x;G    # pat = hold + pat
  /(([^$b]+$b){$((n-1))}[^$b]+)$b/{s//\1$a/g}
  s/.*\n//      # del fields from prev line
  h             # hold = mod*\n
  /.*$a/{ s///  #  pat = unmodified
          x     # hold = unmodified, pat = mod*\n
        }            
  p             # print line"  input_file
于 2012-04-14T15:00:37.957 回答
1
# Get params and create part of the regex.
my $delim   = "\\" . shift;
my $n       = shift;
my $repl    = shift;
my $wild    = '.*?';
my $pattern = ($wild . $delim) x ($n - 1);

# Slurp.
$/       = undef;
my $text = <>;

# Replace and print.
$text =~ s/($pattern$wild)$delim/$1$repl/sg;
print $text;
于 2012-04-14T16:11:23.673 回答
1

我在 bash 脚本中有一个想法:

perl -pe 's/,/(++$n % 3 == 0) ? "|" : $&/ge'  data.txt

那会成功的。

于 2017-05-24T16:32:33.467 回答