sed:仅在两个位置之间替换一个字符

时间:2013-02-04 18:15:58

标签: bash sed

对于这个看似简单的问题感到抱歉,但是花了太长时间试图在任何地方找到解决方案并尝试不同的sed选项。 我只需要在文本文件中用逗号替换所有点,但只需要在两个位置之间。 例如,来自:

1.3.5.7.9

1.3,5,7.9

所以,替换。在3至7位之间。 谢谢!

编辑:对不起,我假装简化了问题,但由于我的问题缺乏细节,前三个答案都没有工作,让我更深入一点。重要的一点是在不知道字符串其余部分的情况下,在一个位置间隔中用逗号替换所有点:

Here some text. I don't want to change. 10.000 usd  234.566 usd Continuation text.
More text. No need to change this part.    345 usd   76.433 usd Text going on. So on.

这是一个固定宽度的文本文件,在列中,我需要更改数字的国际格式,用逗号替换点。我只知道我需要搜索并最终替换点的初始和最终位置。显然,并非所有数字都有点(只有超过1000点)。 感谢。

5 个答案:

答案 0 :(得分:2)

在澄清问题后重写答案:

仅使用sed很难处理,但可以使用cutpaste等其他标准实用程序进行简化:

$ start=40
$ end=64
$ paste -d' ' <(cut -c -$((start-1)) example.txt) \
> <(cut -c $((start+1))-$((end-1)) example.txt | sed 'y/./,/') \
> <(cut -c $((end+1))- example.txt)
Here some text. I don't want to change. 10,000 usd  234,566 usd Continuation text.
More text. No need to change this part.    345 usd   76,433 usd Text going on. So on.

>只表示前一行的继续。<是真实的。这当然是非常低效的,但在概念上很简单。

我使用了所有+1-1内容来摆脱多余的空间。不确定你是否需要它。

一种纯粹的解决方案(自己动手):

$ sed "s/\(.\{${start}\}\)\(.\{$((end-start))\}\)/\1\n\2\n/;h;s/.*\n\(.*\)\n.*/\1/;y/./,/;G;s/^\(.*\)\n\(.*\)\n\(.*\)\n\(.*\)$/\2\1\4/" example.txt
Here some text. I don't want to change. 10,000 usd  234,566 usd Continuation text.
More text. No need to change this part.    345 usd   76,433 usd Text going on. So on.

GNU sed

$ sed -r "s/(.{${start}})(.{$((end-start))})/\1\n\2\n/;h;s/.*\n(.*)\n.*/\1/;y/./,/;G;s/^(.*)\n(.*)\n(.*)\n(.*)$/\2\1\4/" example.txt 
Here some text. I don't want to change. 10,000 usd  234,566 usd Continuation text.
More text. No need to change this part.    345 usd   76,433 usd Text going on. So on.

答案 1 :(得分:1)


我试图简化正则表达式,但它更宽容。

echo 1.3.5.7.9 | sed -r "s/^(...).(.).(..)/\1,\2,\3/"
1.3,5,7.9

PS:它不适用于BSD sed。

答案 2 :(得分:1)

$ echo "1.3.5.7.9" |
gawk -v s=3 -v e=7 '{
   print substr($0,1,s-1) gensub(/\./,",","g",substr($0,s,e-s+1)) substr($0,e+1)
}'
1.3,5,7.9

答案 3 :(得分:1)

这在纯sed中相当尴尬。如果您没有严格限制为sed,我建议您使用其他工具执行此操作。 Ed Morton基于gawk的解决方案可能是解决这个问题最不尴尬(没有双关语)的方法。

以下是使用sed执行grunt工作的示例,但为了简单起见,将其包装在bash函数中:

function transform () {
    line=$1
    start=$2
    end=$3
    # Save beginning and end of line
    front=$(echo $line | sed -e "s/\(^.\{$start\}\).*$/\1/")
    back=$(echo $line | sed -e "s/^.\{$end\}//")
    # Translate characters
    line=$(echo $line | sed -e 'y/\./,/')
    # Restore unmodified beginning/end
    echo $line | sed -e "s/^.\{$start\}/$front/" -e "s/\(^.\{$end\}\).*$/\1$back/"
}

将此功能称为:

$ transform "1.3.5.7.9" 3 7
1.3,5,7.9

答案 4 :(得分:0)

谢谢大家。 我发现的(不是我的优点)作为简单的解决方案是:

  1. 对于固定宽度的文件:

    awk -F "" 'OFS="";{for (j=2;j<= 5;j++) if ($j==".") $j=","}'1
    
  2. 将所有点从第2位置更改为第5位。

    1. 对于制表符分隔的字段文件:

      awk -F'\t' 'OFS="\t" {for (j=2;j<=5;j++) gsub(/\./,",",$j)}'1
      
    2. 将所有点从第2场变为第5场。

      希望可以帮助某人:无法想象在开始时它会如此艰难。