2011-08-31 85 views
2

我有一个包含城市和数字的文件。这是一个csv文件对数字范围使用sed命令

New York , 23456  
chicago, 123,456,789,889981(2-6)  
phoenix 123,76(0-3)  

文件中的范围号我想用每个数字替换它。例如,我想将889981(2-6)更改为8899812,8899813,8899814,8899815,8899816并插入同一行。我能在sed中做到吗?它需要扫描整个文件并进行更换。

+0

也许问题的[超级用户](http://superuser.com/)...在Perl –

回答

4

sed算术不太好;我想这不是不可能的,但也不是很简单。我的建议是使用适当的脚本语言,例如awk,perl或python(如果您不熟悉它们中的任何一种,也许是Python;如果您希望尽可能少的内存占用,请使用awk;如果您已经知道Perl ,无论如何,使用Perl)。

perl -pe 's/(\d+)\((\d+)-(\d+)\)$/ join (",", 
      (join ("", $1, $2) .. join ("", $1, $3))) /ge' file 
+1

这么简单得多使用'''范围操作员! –

+1

如果范围类似'(0-12)',你可能想要使用加法而不是连接。为什么使用'join(“,$ 1,$ 2)'而不是$ 1。 $ 2'? –

+0

没有太大区别。事实上,我相信两者都会编译成相同的字节码。 – tripleee

2

不,这超出了你只用正则表达式所能做的。您需要添加更强大的功能,例如perlpythonawk,或者您最喜欢在家中使用的任何设备。

+0

感谢您的信息 – Arav

+0

请注意,它应该说“...与sed兼容的正则表达式”。你可以在perl正则表达式中做到这一点,但这些基本上都是完整的。 –

1

使用awk(@glenn杰克曼可能会发布一些 ,这是否在不超过5行)解决方案:

# join.awk --- join an array into a string 
function join(array, start, end, sep, result, i) 
{ 
    if (sep == "") 
     sep = " " 
    else if (sep == SUBSEP) # magic value 
     sep = "" 
    result = array[start] 
    for (i = start + 1; i <= end; i++) 
     result = result sep array[i] 
    return result 
} 


function range(input) { 
    split(input, a, "[(-)]") 
    # [1] is startvalue, [2] is start and stop for range 
    split(a[2], b, "-") 
    # [1] is start range, [2] is stop range 
    # create 1st number by appending start range to start value 
    c[1] = a[1] b[1] 
    n=2 
    for(i=b[1]; i<=b[2]; i++){ 
     c[n] = c[n-1] + 1 
     n++ 
    } 
    return join(c, 1, b[2], ",") 

} 

# a line containing a - 
/-/ { 
    for(i=1;i<=NF;i++){ 
     if ($i ~ /-/) { 
     printf("%s,", range($i)) 
     } 
     printf("%s,", $i) 
    } 
    print "" 
} 
!/-/{print} 
+0

我会接受这个挑战! –

+0

感谢您的信息。我如何运行? – Arav

+0

@Arav,你不用,用glenn jackman或carlpett来代替。 (运行它为'awk -F,-f script.awk inputfile') –

1

需要gawk的3个参数的match()功能:

gawk ' 
    BEGIN {OFS = FS = ","} 
    match($NF, /([0-9]+)\(([0-9]+)-([0-9]+)\)/, ary) { 
     NF-- 
     for (n=ary[2]; n <= ary[3]; n++) { 
      $(NF+1) = 10 * ary[1] + n 
     } 
    } 
    {print} 
' 

我假设(基于样本)该范围仅出现在最后一个以逗号分隔的字段中。

+0

不错!我是对的:-)回到手册页... –

+0

感谢您的信息。当我试图运行它说没有找到gawk。 sun os是操作系统。我做了一个“哪个gawk”,它无法找到gawk。猫< file name> | gawk .......我可以使用什么替代方法? – Arav

+0

@Arav,(1)让你的系统管理员从http://sunfreeware.com安装gawk,或者(2)使用perl。 –

0

这可能会为你工作(GNU仅SED):

sed 's/^\(.*\)\b\([0-9]\+\)(\([0-9]\)-\([0-9]\))/echo "\1" {\2\3..\2\4}/e;s/\([0-9]\),\? \([0-9]\)/\1,\2/g' file 
New York , 23456  
chicago, 123,456,789,8899812,8899813,8899814,8899815,8899816 
phoenix 123,760,761,762,763