如何定义正则表达式以匹配包含分隔符的csv文件中的值?

时间:2015-03-20 16:53:24

标签: regex r awk sed grep

我试图检查来自巴西的一些政府数据,CSV文件使用read.csv和fread(来自data.table R包)给我带来了一些麻烦。 fread指向我错误的一些行,我发现其中一个字段有&#39 ;;'在那里。

坏行的一个例子如下。请注意,第三个字段包含&#39 ;;'。

29561;5001;"Urbanização - Eixo Borda da Baía - Urbanização Mirante do Bonfim e Pedra furada; Bananeiras, Miramar e Alagados IV e V - Salvador - BA";;;48030000.00;BA;SALVADOR;Estado;Ministério das Cidades;71;31/10/2014;11/11/2010;;"12 53'26.843964""S";"38 26'16.689156""O";;

我尝试定义一个正则表达式来替换&#39 ;;' by','或其他什么,我没有得到它。 我最终使用awk来查找记录中具有不同字段数的所有行,幸运的是它在56k +行文件中只有5行。

我可以使用什么正则表达式替换&#39 ;;'在那些领域? 我在grep中尝试了下面的正则表达式(gnu grep版本2.6.3) (一个数字后跟一个分号后跟双引号,后跟任何后跟分号后跟任何后跟双引号的内容)。 [0-9] +; \" ;? \"

3 个答案:

答案 0 :(得分:2)

我不认为Regex是一个很好的解决方案。尝试使用R中的“read.table”方法。它允许您指定分隔符,引号,标题和其他几个选项。可能需要几次尝试才能使一切变得完美,但它应该有效。尝试这样的事情:

data=read.table(file="filename.txt",sep=";",quote="\"",na.strings="",header=F,stringsAsFactors=F)

查看help(read.table)了解完整详情。

答案 1 :(得分:1)

我认为最好的解决方案是尝试替换字段中的分号。在字段中找到字段分隔符是很常见的 - 这就是内容周围的双引号所针对的内容。

任何半合适的CSV解析器都可以处理这种格式。例如,在python中使用csv核心模块:

import csv
with open('file') as file:
  reader = csv.reader(file, delimiter=';')
  for row in reader:
    print '\n'.join(row)

这给出了输出:

29561
5001
Urbanização - Eixo Borda da Baía - Urbanização Mirante do Bonfim e Pedra furada; Bananeiras, Miramar e Alagados IV e V - Salvador - BA


48030000.00
BA
SALVADOR
Estado
Ministério das Cidades
71
31/10/2014
11/11/2010

12 53'26.843964"S
38 26'16.689156"O

如您所见,包含分号的字段仍然被正确解析为单个字段。

老实说,我很惊讶R模块不起作用。也许有一些方法来定义引用字符?

答案 2 :(得分:0)

使用GNU awk for FPAT(参见http://www.gnu.org/software/gawk/manual/gawk.html#Splitting-By-Content):

$ cat tst.awk
BEGIN { OFS=";"; FPAT="([^"OFS"]*)|(\"[^\"]*\")" }
{
    for (i=1; i <= NF; i++) {
        gsub(OFS,",",$i)
    }
    print
}
$ gawk -f tst.awk file     
29561;5001;"Urbanização - Eixo Borda da Baía - Urbanização Mirante do Bonfim e Pedra furada, Bananeiras, Miramar e Alagados IV e V - Salvador - BA";;;48030000.00;BA;SALVADOR;Estado;Ministério das Cidades;71;31/10/2014;11/11/2010;;"12 53'26.843964""S";"38 26'16.689156""O";;