【问题标题】:Parsing a csv file into an array using awk使用 awk 将 csv 文件解析为数组
【发布时间】:2016-05-08 18:57:13
【问题描述】:

我必须解析一个 csv 文件并将其内容转储到 mysql 表中。

# myfile.csv # 内容 # 示例标题 “带引号的 header1”,不带引号的 header2,“header3”,header4,hheader5 "示例文本",2,3,4,"MoreText,带逗号" "Text2 转义 \"",8,6,7,9 "文本3",876,0.6,7,10

第一个输出

rowid|header1 带引号|示例文本|myfile 1|不带引号的标题2|2|我的文件 1|header3|3|我的文件 1|header4|4|我的文件 1|header5|MoreText,带逗号|myfile 2|header1 带引号|Text2 带转义 \"|myfile 2|header2 不带引号|8|我的文件 2|header3|6|我的文件 2|header4|7|我的文件 2|header5|9|我的文件 3|header1 带引号|text3|myfile 3|header2 不带引号|876|我的文件 3|header3|0.6|我的文件 3|header4|7|我的文件 3|header5|10|我的文件

在第二个输出中,我需要水平对齐自定义标题。例如

rowid|"header1 带引号"|"header3"|header4|文件名 1|示例文本|3,4,myfile 2|Text2 带有转义的 \"|6|7|myfile 3|文本3|0.6|7|我的文件

对于第二个输出,它可以是我选择的任何标题集。 然后我可以使用 load data infile 将这两个输出数据加载到 mysql 表中。寻找 awk 脚本来实现这一点。需要帮助请叫我。发送。

【问题讨论】:

  • 请原谅未格式化的数据。还在学习中。。
  • @edmorton 按要求编辑了问题。
  • 如果您需要使用嵌入的逗号和引号来处理 CSV 的全部复杂性,您可能最好使用 Python 或 Perl 以及它们提供的 CSV 模块,或者像 CSVfix 这样的专业工具(它曾经托管在 Google Code 上,但现在已经关门了;这些天我不确定它的官方来源,这很尴尬)。

标签: mysql file csv awk


【解决方案1】:

这应该可行:

{
    if(NR==1)
        split($0,header,",")
    else
    {
        split($0,line,",")
        for (i in line)  
        {
            gsub(/^[ \t]+|"|[ \t]+$)/, "", header[i]); 
            gsub(/^[ \t]+|"|[ \t]+$)/, "", line[i]); 
            print header[i]"|"line[i]"|"FILENAME
        }
        print ""
    }
}

基本上它将第一行存储在header 数组中,然后将splits 存储在elem 数组中的每一行中,并修剪掉前导和尾随空格或制表符。最后,它组成输出字符串。

输出:

header1|text1|file2
header2|2|file2
header3|3|file2
header4|4|file2
hdeader5|moretext|file2

header1|text2|file2
header2|8|file2
header3|6|file2
header4|7|file2
hdeader5|9|file2

header1|text3|file2
header2|876|file2
header3|0.6|file2
header4|7|file2
hdeader5|10|file2

您可以通过删除最后一个 print "" 语句来消除每个块之间的换行符。

【讨论】:

  • Tx @Cynical。我也忘了提到文本之间存在的逗号。例如说:“一些,更多的文字,中间有逗号”。这些会是个问题吧?刚刚在我的 csv 文件上运行这个脚本并意识到我的错误。有什么建议吗?
  • 示例:“一些文本”,文本,“一些文本,带逗号”,“引号中的普通文本”。再次发送。
  • 是的,这可能是个问题... 带逗号的文本是否有可能总是括在引号之间?
  • 预处理将您的字段分隔符从逗号更改为您的字段、制表符、波浪号、管道中不包含的内容...
  • 是的,文本中带逗号的总是在引号中。没有逗号的可能在引号内,也可能不在引号内。因此,您可能会在同一个文件中包含诸如:文本和“文本”和“文本,带逗号”之类的词。
【解决方案2】:

我将把输出格式留给您,但这里是在处理嵌入的逗号和转义引号以及围绕某些字段的不需要的空格之后创建字段数组的方法,以便您可以对它们做任何您想做的事情:

$ cat tst.awk
BEGIN { FPAT = "([^,]*)|(\"[^\"]+\")" }
{ sub(/#.*/,"") }
NF {
    # replace all escaped quotes with a newline and resplit the record
    gsub(/\\"/,RS)

    for (i=1;i<=NF;i++) {
        # restore the escaped quotes in this field
        gsub(RS,"\\\"",$i)

        f[i] = $i
    }

    for (i=1;i<=NF;i++) {
        # remove this to leave leading/trailing white space:
        gsub(/^[[:space:]]+|[[:space:]]+$/,"",f[i])

        # remove this to leave quotes around fields:
        gsub(/^"|"$/,"",f[i])

        print NR, NF, i, "<" f[i] ">"
    }
    print "----"
}

.

$ awk -f tst.awk file
4 5 1 <header1 with quotes>
4 5 2 <header2withoutquotes>
4 5 3 <header3>
4 5 4 <header4>
4 5 5 <hdeader5>
----
5 5 1 <Sample Text>
5 5 2 <2>
5 5 3 <3>
5 5 4 <4>
5 5 5 <MoreText, with commas>
----
6 5 1 <Text2 with escaped \">
6 5 2 <8>
6 5 3 <6>
6 5 4 <7>
6 5 5 <9>
----
7 5 1 <Text3>
7 5 2 <876>
7 5 3 <0.6>
7 5 4 <7>
7 5 5 <10>
----

上面将 GNU awk 用于 FPAT,而其他 awk 则需要 while(match(...)) 循环。

请参阅 http://www.gnu.org/software/gawk/manual/gawk.html#Splitting-By-Content 了解 FPAT 如何将输入拆分为字段。除此之外:

  1. 第一个 sub() 和测试 NF 丢弃 cmets 和空行。
  2. 循环前的gsub() 将每次出现的\" 替换为换行符,这样转义的引号就不会妨碍字段拆分,并且此操作适用于整个记录的事实会导致awk 重新拆分之后,FPAT 在该点再次应用,确保原始 \"s 对进入循环的字段没有影响。
  3. 第一个循环中的 gsub() 会恢复当前字段中最初存在的所有 \"s
  4. 第二个循环中的第一个 gsub() 只是修剪当前字段的所有前导和尾随空白。
  5. 第二个循环中的第二个 [可选] gsub() 从字段中删除开始/结束引号。

其余的应该是显而易见的。我正在剥离使用 f[] 的前导/尾随空格和引号,而不是填充它的位置,因为您似乎需要至少 2 个不同的输出,一个带有引号,一个不带引号,但您可以选择其中任何一个 @987654338 @s 完成了。

要学习 awk - 获取 Arnold Robbins 所著的《Effective Awk programming, 4th Edition》一书。

【讨论】:

  • 发送@edmorton。感谢您的努力。
猜你喜欢
  • 2016-05-04
  • 2014-10-19
  • 2015-06-20
  • 1970-01-01
  • 1970-01-01
  • 2012-12-16
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
相关资源
最近更新 更多