无法正确读取csv文件(几乎删除了一半的行)

ttvkxqim  于 2023-07-31  发布在  其他
关注(0)|答案(3)|浏览(129)

我想用R读入一个csv文件。它使用分号作为分隔符,并使用双引号作为引号。
但是,该文件有一些有问题的单元格(例如有些在文本单元格中有一个双引号或文本中有一个分号),这导致R无法正确地读取文件。
由于我不能上传文件,所以下面是用文本编辑器打开csv时的样子:

"X1";"X2";"X3"
"1";"0";"test"
"37129";"11746; weird";"weird "thing""
"27929";"1";"xyz Limited"

字符串
第1行包含标题。在第3行中,您可以看到X2值在“11746”之后有一个分号,X3值在“thing”之前有一个额外的双引号。
因此,在这个小示例中,当用readr::read_csv2(file = my_file.csv)读取这个文件时,它看起来很好,但实际上并不好(注意,我的真实文件有13k行)。例如,我们希望在“thing”前后看到双引号。
当我使用readr::read_csv2(file = my_file.csv, quote = "")时,第2行的值由于分号而被移位。
有什么想法,我该如何解决这个问题?
预期产出将是:

# A tibble: 3 × 3
     X1 X2           X3             
  <dbl> <chr>        <chr>          
1     1 0            "test"         
2 37129 11746; weird "\"weird thing\""
3 27929 1            "xyz Limited"

trnvg8h3

trnvg8h31#

这不是符合标准的分号CSV。"thing"引号应该是双引号才能转义,如在"37129";"11746; weird";"weird ""thing"""中。创建该文件的任何内容都不符合标准。“
我们可以尝试使用regex来解析内容,将嵌入的"引号改为双引号""(而不更改括起来的" s),可能是这样的:

## on the shell, not in R
$ sed -E 's/([^;])"([^;])/\1""\2/g' quux.csv > newquux.csv

个字符
人们可能会在R中这样做,这通常是好的。但是,如果csv文件很大,那么这将导致R的内存消耗不必要的增长......同样,只有在文件很大时才是问题。

read.csv2(
  text = gsub('(?<=[^;])"(?=[^;])', '""',
              readLines("quux.csv"), perl = TRUE))
#      X1           X2            X3
# 1     1            0          test
# 2 37129 11746; weird weird "thing"
# 3 27929            1   xyz Limited


上述两种方法都适用于readr::read_csv2

readr::read_csv2("newquux.csv")
readr::read_csv2(
  I(gsub('(?<=[^;])"(?=[^;])', '""',
         readLines("quux.csv"), perl = TRUE)))


(The I(..)在这里是必需的,因为否则它会选择查找名为"X1";"X2";"X3"的文件。)

vx6bjr1n

vx6bjr1n2#

我认为你需要的是指定"作为引号字符,我得到了我认为你想要的:

read.table("test.csv", sep=";", quote = "\"", header= FALSE)

字符串
但是,引号被删除,因为它们是引号字符,您是否也要保留它们?
输出:

V1           V2          V3
1    X1           X2          X3
2     1            0        test
3 37129 11746; weird weird thing
4 27929            1 xyz Limited

ekqde3dh

ekqde3dh3#

这是一种非标准的文件格式,但我们可以使用readLines读取它,然后用文件中没有的其他字符替换分隔引号-这里我们使用单引号作为该字符。

"my_file.csv" |>
  readLines() |>
  gsub('^"|"$', "'", x = _) |>  # replace " with ' at start & end of each line
  gsub('";"', "';'", x = _) |>  # replace ";" with ';'
  read.csv2(text = _, quote = "'")
##      X1           X2            X3
## 1     1            0          test
## 2 37129 11746; weird weird "thing"
## 3 27929            1   xyz Limited

字符串
我们可以用这段代码来检查文件中有哪些字符。任何未列出的字符都可以用作新的引号字符。

"my_file.csv" |>
  readLines() |>
  strsplit("") |>
  unlist() |>
  table() |>
  names() |>
  cat("\n")
## " ; 0 1 2 3 4 6 7 9 d e g h i L m n r s t w x X y z


或者我们可以用这个代码来检查一个特定的字符,这里是单引号,是否出现在文件中。如果像问题中的示例输入那样返回1,则该字符不会出现,否则会出现。

max(count.fields("my_file.csv", sep = "'", quote = ""))
## [1] 1

相关问题