使用unix脚本将空格分隔符转换为逗号分隔符文件

时间:2014-04-10 19:41:14

标签: shell unix csv scripting export-to-csv

我有一个空格分隔值的文件,我需要将其更改为以逗号分隔的值。但我有一些字符串列引用""(双引号),我可能在字符串列中有空格。我需要取消",并且需要使用,作为分隔符生成文件。

请帮助您使用UNIX脚本来转换它?

示例数据:

abcd "Bala Chuppala" 1 200 "" "Norway" "" ? ? 9 88‏ 

ab "Joh Tanni S V S" 200 2 ? "Swiss" 1 100 200 ? 

预期输出:

abcd,Bala Chuppala,1,200,,Norway,,?,?,9,88‏ 

ab,Joh Tanni S V S,200,2,?,Swiss,1,100,200,? 

由于

3 个答案:

答案 0 :(得分:1)

这有点难看,因为我的C技能很生疏,但效果还不错......

另存为redelimit.c并按照以下方式编译:

gcc -o redelimit redelimit.c

cc -o redelimit redelimit.c

然后像这样运行

./redelimit

如果要保存输出,请执行以下操作:

./redelimit > newfile.csv

它希望输入文件被称为input.csv

#include <stdio.h>
#include <string.h>

FILE *fp;

int main()
{
   int i,n;
   int inquotes;
   char line[1024];

   fp = fopen ("input.csv", "r");

   /* Loop through all lines in file */
   while(fgets(line, sizeof(line), fp) != NULL)
   {
      /* Remember if we are inside double quotes so we know what to do with spaces */
      inquotes=0;

      /* Parse each character in line */
      int len = strlen(line);
      for(i=0;i<len;i++){

         /* If these are double quotes, toggle value of "inquotes" variable */
         if(line[i]=='"'){
           inquotes=1-inquotes;
           continue;
         }

         if(line[i]==' '){
            if(inquotes){putchar(' ');} else {putchar(',');}
            continue;
         }

         putchar(line[i]);
      }
   }
   fclose(fp);
}

<强>输出

abcd,Bala Chuppala,1,200,,Norway,,?,?,9,88
ab,Joh Tanni S V S,200,2,?,Swiss,1,100,200,?,

答案 1 :(得分:1)

在很多方面,custom C program显示的Mark Setchell是一个很好的解决方案;它简洁明了,相对容易使用。 (如果从标准输入中获取输入,或者如果没有文件名,则从标准输入读取文件名参数会更容易。对于通用工具,硬编码文件名很少是个好主意)

如果您打算尝试使用标准工具,那么您将使用正则表达式。乍一看,您选择的工具包括sedawk,Perl和Python。如果您使用sed,则它必须是具有扩展正则表达式支持的版本(至少允许替代,|);没有它,我认为你可以安全地进行映射。事实证明,sub中的gsubawk函数不够强大;他们不支持记住字符串&#39;在替换以外的整个匹配字符串。

你需要做什么?

  • 任何零或多的序列,而不是双引号或空格&#39;然后是空格映射到以逗号结尾的字段(注意如果输入数据中有逗号,那么由于interloper,输出中会有一个额外的字段)。
  • 双引号的任何序列,后跟零或更多,而不是双引号&#39;然后双引号和空格映射到零或更多&#39;部分后面跟一个逗号。
  • 可以说,如果第二个双引号后面没有空格,则会出现格式错误 - 除非"Johnny ""The Singer"" Cholmondeley"等转义规则映射到Johnny "The Singer" Cholmondeley。即便如此,严格来说,只有另一个双引号才有效。
  • 该行末尾的双引号字符串映射到未加引号的字符串。

忽略预先存在的逗号和嵌入式双引号,最简单的方法是分两步进行更换:

  1. 用逗号替换适当的空格。
  2. 删除周围的双引号。
  3. 例如,在Perl或具有ERE支持的sed中:

    perl -p -e 's/([^ "]*|"[^"]*") /\1,/g; s/"([^"]*)"/\1/g' "$@"
    sed  -E -e 's/([^ "]*|"[^"]*") /\1,/g; s/"([^"]*)"/\1/g' "$@"   # Mac OS X, BSD
    sed  -r -e 's/([^ "]*|"[^"]*") /\1,/g; s/"([^"]*)"/\1/g' "$@"   # GNU
    

    Python解决方案更冗长(或者,至少,根据我对Python的知识水平,它是):

    #!/usr/bin/python
    from __future__ import print_function
    import re
    import fileinput
    
    ssv = re.compile(r'([^ "]*|"[^"]*") ')
    qqv = re.compile(r'"([^"]*)"')
    
    for line in fileinput.input():
        line = ssv.sub(r'\1,', line)
        line = qqv.sub(r'\1', line)
        print(line, end='');
    

    请注意,该脚本适用于Python 2(2.7测试,名义上为2.6,但未提前导入以前不可用)以及Python 3(3.4测试)。

答案 2 :(得分:0)

如果你对编译器有恐惧感,我在awk中做了同样的事情: - )

#!/usr/bin/awk -f
{
    inq=0
    len=length($0)
    for(i=1;i<=len;i++){
      c=substr($0,i,1)
      if(c=="\""){inq=1-inq}
      if(c==" "){
         if(inq==1)
         {
            printf " "
         } else {
            printf ","
         }
      } else {
         printf "%s",c
      }
    }
    printf "\n"
}

另存为marksscript并按此运行

chmod +x marksscript
./marksscript < input.csv