【问题标题】:Read csv file with hidden or invisible character ^M读取带有隐藏或不可见字符的 csv 文件 ^M
【发布时间】:2014-02-14 18:26:40
【问题描述】:

我试图读取包含隐藏或不可见字符的 *.csv 文件,但未成功。文件内容如下所示:

my.data2 <- read.table(text = '
Common.name, Scientific.name, Stuff1, Stuff2
Greylag.Goose, Anser.anser, AAC, rr
Snow.Goose, Anser.caerulescens, AAC, rr
Greater.Canada.Goose, Branta.canadensis, AAC, rr
Barnacle.Goose, Branta.leucopsis, AAC, rr
Brent.Goose, Branta.bernicla, AAC, rr
', header = TRUE, sep=',', stringsAsFactors = FALSE)

请注意,上面的read.table 命令可以正确读取数据。但是,read.csv 无法正确读取文件,因为在许多行中,第二个空格后面有一个隐藏字符。在某些行中,在第一个空格之后还有一个隐藏字符。在某些行中没有隐藏字符。例如:

setwd('c:/users/mmiller21/simple R programs')

my.data <- read.csv('invisible.delimiter2.csv', header = TRUE)
my.data

返回:

            Common.name    Scientific.name Stuff1 Stuff2
1         Greylag.Goose        Anser.anser              
2                   AAC                 rr              
3            Snow.Goose                                 
4    Anser.caerulescens                                 
5                   AAC                 rr              
6  Greater.Canada.Goose  Branta.canadensis    AAC     rr
7        Barnacle.Goose   Branta.leucopsis              
8                   AAC                 rr              
9           Brent.Goose    Branta.bernicla              
10                  AAC                 rr              

更具体地说,如果我在记事本中打开 *.csv 文件并使用右箭头键将光标沿第一行数据移动,我必须按两次右箭头键才能移过第一个 @987654328 @在AAC.

以下行不能解决问题:

my.data <- read.csv('invisible.delimiter2.csv', sep=',', header = TRUE)

根据我的经验,制表符是一种相当常见的隐藏字符或分隔符。但是,我尝试搜索和替换选项卡,但没有帮助。

我也尝试将 *.csv 文件转换为 *.txt 文件,但返回以下内容:

> my.data3 <- read.table('invisible.delimiter2.txt', sep=',', header = TRUE)
Error in scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  : 
  line 1 did not have 4 elements
> my.data3
Error: object 'my.data3' not found

我不熟悉其他可能的解决方案。该文件太大,无法手动在每个空格中搜索隐藏字符并将其删除。

感谢您就如何读取此类文件或如何在将文件读入 R 之前查找和删除隐藏字符提供任何建议。

如果有帮助,我最初是通过从 Wikipedia 复制表格来获取数据的。也许这可能有助于识别隐藏的角色。

编辑

感谢下面的 cmets,我使用 gVim 7.3 打开了示例数据文件。该软件显示隐藏字符并将其显示为^M。不幸的是,我无法在 gVim 7.3 中通过简单的查找和替换从数据文件中删除该字符。如果以及当我弄清楚如何删除^M 时,我将在此处发布该方法。

这是一篇关于如何使用 Perl 删除 ^M 的帖子。

In Perl, how to remove ^M from a file?

希望我能弄清楚如何使用 R 或文本编辑器将其删除

这是存储示例 *.csv 文件的链接。

https://github.com/markwmiller/Rcode/blob/93d07bd2e389e516b6da92017e025a1e97173db0/invisible.delimiter2.csv

以及指向同一站点上同一文件的替代链接:

https://github.com/markwmiller/Rcode

【问题讨论】:

  • 你能上传一个文本文件的前 10-20 行吗?
  • 我不知道如何上传文件。如果我发现我会上传一些数据。
  • 您必须使用第三方网站。像 pastebin 或类似的东西。
  • 等一下 - 你说 read.table 可以读取数据,但 read.csv 没有?所以嗯,我认为这里有一个解决方案......不确定它可能是什么......嗯,哦,是的,“只需使用read.table”?
  • @Spacedman 也许我表达得不好。当我写the above read.table command reads the data correctly 时,我的意思是如果将引用的代码复制并粘贴到 R 中,R 将正确读取数据,但如果尝试读取外部文件,则会导致错误。也许您的建议是将大数据文件的全部内容直接复制并粘贴到 R 中,然后尝试以这种方式读取数据。这可能行得通,但它似乎充其量只是一个权宜之计。希望有人能够提供一种方法来有效地从文件中删除隐藏字符,而不管文件大小。

标签: r csv


【解决方案1】:

在 gVim 中,您应该能够通过键入以下内容来删除 ^M 字符:

:%s/<ctrl>V<ctrl>M//g<return>

如果你输入正确,它在 gVim 中会看起来像 ':%s/^M//g'。当你按下回车键时,gVim 会搜索('s')第一个和第二个斜杠之间的内容,并用第二个和第三个斜杠之间的内容替换它,全局('g')。

注意:如果你在 Windows 机器上并且 V 似乎在粘贴文本,那么 gVim 可能配置了“windows 行为”。在这种情况下,请使用 QM 而不是 VM。

当我将您的示例文件加载到 gVim 7.3 中时,它看起来像这样:

输入字符后

:%s/<ctrl>V<ctrl>M//g

但在点击返回之前,我看到了这个:

点击返回后,我看到了这个:

然后您可以执行 File->Save 或 File->Save As,这符合您的预期。

【讨论】:

  • 我不清楚我在哪里输入的。将数据文件导入 gVim 后,我必须使用菜单打开特定窗口来输入吗?
  • 将文件加载到 gVim 后,请确保您处于命令模式(如果不确定,请点击几次转义)。然后键入上面的字符序列,以冒号、百分号、小写的 's' 等开头。最后按回车键,gVim 将删除 ^M 字符。顺便说一句,按顺序按 VM 是故意的。这就是你在 gVim 中输入控制字符的方式。
  • 谢谢。我想我快到了。我目前的问题是,点击 v 会粘贴到我在大约 12 小时前从某处复制的最新文本字符串中。我通常通过点击 c 将文本复制到 gVim 之外,然后用 v 将其粘贴。如何从内存中删除该文本字符串,以便 gVim 不会在我的文件中搜索不相关的字符串?
  • 这很奇怪。在 gVim 中,如果您处于命令模式(确定按转义键) V 不应该粘贴任何内容:它应该在您正在构建的命令中插入一个插入符号。当您点击 M 时,您应该从我的原始帖子中获得命令的第一部分。你有什么版本的 gVim?检查帮助->版本或帮助->关于。
  • 您的 _vimrc 文件可能有问题。见here
【解决方案2】:

这是一个解决方案,使用scan 读取数据,matrix 对其进行结构化,data.frame 将其制成数据框:

readF <- function(path, nfields=4){    
    m = matrix(
          gsub(",","",scan(path,what=rep("",nfields))),
              ncol=nfields,byrow=TRUE)
    d = data.frame(m[-1,])
    names(d)=m[1,]
    d
}

所以首先检查文件是否重复您的问题:

> read.csv("./invisible.delimiter2.csv")
            Common.name    Scientific.name Stuff1 Stuff2
1         Greylag.Goose        Anser.anser              
2                   AAC                 rr              
3            Snow.Goose                                 
4    Anser.caerulescens                                 
5                   AAC                 rr              
6  Greater.Canada.Goose  Branta.canadensis    AAC     rr
7        Barnacle.Goose   Branta.leucopsis              
8                   AAC                 rr              
9           Brent.Goose    Branta.bernicla              
10                  AAC                 rr        

然后看看我的函数是否解决了:

> readF("./invisible.delimiter2.csv")
Read 24 items
           Common.name    Scientific.name Stuff1 Stuff2
1        Greylag.Goose        Anser.anser    AAC     rr
2           Snow.Goose Anser.caerulescens    AAC     rr
3 Greater.Canada.Goose  Branta.canadensis    AAC     rr
4       Barnacle.Goose   Branta.leucopsis    AAC     rr
5          Brent.Goose    Branta.bernicla    AAC     rr

请随意挑选功能,看看它是如何工作的。

我怀疑问题的根源是 ^M 在字段数据中,并且因为您的字段没有被引用,所以 R 无法判断它是真正的行尾还是字段中的行尾。在read.csv 等的文档中,有一些关于引用字段中嵌入换行符的注释。

【讨论】:

  • 感谢您提供的功能。当通用名称和科学名称中有一个空格而不是一个点并且Stuff1Stuff2 包含多个单词并且开头有一个^M 时,我试图让该函数工作通用名称和/或科学名称的末尾和/或Stuff2 的末尾。如果我可以针对这些场景修改函数,我可能会在此处发布。
【解决方案3】:

这是可以处理字段中的空格(即多个单词)的代码:

nfields <- 4

bb <- readLines('c:/users/mmiller21/simple R programs/invisible.delimiter4.csv')
bb

pattern <- "(?<=\\,)(?=)"                  # split on commas
cc <- strsplit(bb, pattern, perl=TRUE)
dd <- unlist(cc)
ee <- dd[dd != ' ' & dd != '' & dd != ','] # remove empty elements
ff <- gsub(",", "", ee)                    # remove commas

m = matrix(ff, ncol=nfields, byrow=TRUE)   # store data in matrix

# returns string w/o leading or trailing whitespace
trim <- function (x) gsub("^\\s+|\\s+$", "", x)
nn <- trim(m)
nn

以下是原始数据集的内容:

Common.name, Scientific.name, Stuff1, Stuff2
Greylag Goose, Anser anser, AAC aa, rr bb
Snow Goose, Anser caerulescens, AAC aa aa, rr bb bb
Greater Canada Goose, Branta canadensis, AAC, rr bb
Barnacle Goose, Branta leucopsis, AAC aa, rr
Brent Goose, Branta bernicla, AAC, rr bb bb bb

我简单地删除了通用名称和学名中的点,并在第三列和第四列添加了额外的文本。

这是输出:

     [,1]                   [,2]                 [,3]        [,4]         
[1,] "Common.name"          "Scientific.name"    "Stuff1"    "Stuff2"     
[2,] "Greylag Goose"        "Anser anser"        "AAC aa"    "rr bb"      
[3,] "Snow Goose"           "Anser caerulescens" "AAC aa aa" "rr bb bb"   
[4,] "Greater Canada Goose" "Branta canadensis"  "AAC"       "rr bb"      
[5,] "Barnacle Goose"       "Branta leucopsis"   "AAC aa"    "rr"         
[6,] "Brent Goose"          "Branta bernicla"    "AAC"       "rr bb bb bb"

【讨论】:

    猜你喜欢
    • 2015-12-11
    • 1970-01-01
    • 2022-11-16
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多