【问题标题】:Parsing a CSV with irregular quoting rules using readr使用 readr 解析具有不规则引用规则的 CSV
【发布时间】:2019-02-11 20:06:37
【问题描述】:

我有一个无法用 readr 解析的奇怪 CSV。我们称之为data.csv。它看起来像这样:

name,info,amount_spent
John Doe,Is a good guy,5412030
Jane Doe,"Jan Doe" is cool,3159
Senator Sally Doe,"Sally "Sal" Doe is from New York, NY",4451

如果所有行都像列行下方的第一行——两个字符列后跟一个整数列——这将很容易用read_csv解析:

df <- read_csv("data.csv")

但是,有些行的格式与第二行类似,因为第二列(“info”)包含一个字符串,其中一部分用双引号括起来,一部分没有。这使得 read_csv 不会读取单词 cool 之后的逗号作为分隔符,并且整个下一行被附加到有问题的单元格。

此类问题的解决方案是将FALSE 传递给read_delim() 中的escape_double 参数,如下所示:

df <- read_delim("data.csv", delim = ",", escape_double = FALSE)

这适用于第二行,但被第三行杀死,其中第二列包含一个用双引号括起来的字符串,该字符串本身包含嵌套的双引号一个逗号。

我已阅读 readr 文档,但尚未找到可以解析这两种类型的行的解决方案。

【问题讨论】:

  • 这个 csv 是从哪里来的?这基本上是一个无效的 CSV。我会尝试修复生成数据的过程,而不是尝试破解导入例程来解决它。
  • data.table::fread() 正确读取样本数据。
  • 带有警告Found and resolved improper quoting in first 100 rows
  • @MrFlick 这是 Facebook 每周的广告支出数据。如果您下载第一个并尝试解析“SpendingToDate”文件,您就会明白我的意思。 facebook.com/ads/archive/report/?source=archive-landing-page

标签: r regex tidyverse readr


【解决方案1】:

以下是指定示例对我有用的方法。

使用 read.csv 而不是 read_csv。 这意味着我使用的是数据框而不是 tibble。

#Read the csv, just turned the table you had as an example to a csv.
#That resulted as a csv with one column
a <- read.csv(file = "Book1.csv", header=T) 

#Replace the comma in the third(!) line with just space
a[,1] <-  str_replace_all(as.vector(a[,1]), ", ", " ")

#Use seperate from the tidyer package to split the column to three columns
#and convert to a tibble
a <- a %>% separate(name.info.amount_spent, c("name", "info", "spent"), ",")%>%
as_tibble(a)
glimpse(a)
 $name  <chr> "John Doe", "Jane Doe", "Senator Sally Doe"
 $info  <chr> "Is a good guy", "\"Jan Doe\" is cool", "\"Sally \"Sal\" Doe is from New York NY\""
 $spent <chr> "5412030", "3159", "4451"

【讨论】:

    【解决方案2】:

    您可以使用在有问题的逗号上拆分的正则表达式(使用(*SKIP)(*FAIL)):

    input <- c('John Doe,Is a good guy,5412030', 'Jane Doe,"Jan Doe" is cool,3159',
               'Senator Sally Doe,"Sally "Sal" Doe is from New York, NY",4451')
    
    lst <- strsplit(input, '"[^"]*"(*SKIP)(*FAIL)|,', perl = T)
    
    (df <- setNames(as.data.frame(do.call(rbind, lst)), c("name","info","amount_spent")))
    

    这会产生

                   name                                   info amount_spent
    1          John Doe                          Is a good guy      5412030
    2          Jane Doe                      "Jan Doe" is cool         3159
    3 Senator Sally Doe "Sally "Sal" Doe is from New York, NY"         4451
    

    查看regex101.com 上的表达式演示。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-11
      • 2019-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多