读取具有不同列宽但在 R 中固定分隔符的文本文件

Posted

技术标签:

【中文标题】读取具有不同列宽但在 R 中固定分隔符的文本文件【英文标题】:Reading text file with varying column width but fixed delimiter in R 【发布时间】:2018-03-16 17:41:52 【问题描述】:

我有多个如下所示的 .txt 文件:

header
header
header
header
header
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\AAA AAAAAAAA\AAAAA\BBBB BBBB & BBBBB BBBBB\CAM_07-0008\Farther Downg   Gray Fox                                                                           
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\AAA AAAAAAAA\AAAAA\BBBB BBBB & BBBBB BBBBB\CAM_07-0008\Farther Downg   Direct Register Walk, Gait, Gray Fox, Stop                                         
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\AAA AAAAAAAA\AAAAA\BBBB BBBB & BBBBB BBBBB\CAM_07-0008\Farther Downg   Gray Fox   

最后 2 列的宽度各不相同,但所有列之间总是有 3 个空格(在这种情况下,第 3 列是空的)。

我正在使用此代码读取示例 .txt:

read.fwf(filename.txt,skip=5,widths=c(12,16,19,76,83),fill=T,fileEncoding = "UTF-16")

但是这段代码在这个 .txt 文件上不能正常工作:

header
header
header
header
header
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\AAA AAAAAAAA\AAAAA AA\BBBB BBBB & BBBBB BBBBB\CAM_07-0008\Farther DowngBBB   Gray Fox                                                                           
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\AAA AAAAAAAA\AAAAA AA\BBBB BBBB & BBBBB BBBBB\CAM_07-0008\Farther DowngBBB   Direct Register Walk, Gait, Gray Fox, Stop                                         
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\AAA AAAAAAAA\AAAAA AA\BBBB BBBB & BBBBB BBBBB\CAM_07-0008\Farther DowngBBB   Gray Fox   

有没有一种方法可以读取具有固定分隔符(3 个空格)的 .txt 文件,而不必定义每列的宽度,因为列宽因文件而异。

这些文件也有一些编码问题,所以here是我正在使用的示例文件

【问题讨论】:

你试过 read.table 吗? 是的,我试过 read.table(filename.txt,skip=5,sep=" ",fileEncoding="UTF-16") 和 sep=" " 和 sep="" 和每个扫描时出现错误错误(file = file,what = what,sep = sep,quote = quote,dec = dec,:第 2 行没有 103 个元素 那是因为它在任何空白处分隔,而不仅仅是连续的三个空格。如果您没有太多文件,一个简单的解决方案可能是用制表符替换所有出现的三个空格,然后使用您刚刚尝试过的 read.table 调用。 这些是大文件吗?您可以将它们全部作为原始文本阅读,用gsub 的制表符替换三个空格,然后将其解析为表格输入。或者你在一个类似unix的机器上?您可以阅读 pipe() 并使用 awk 之类的内容快速进行翻译。 我有数百个这样的文件。但它们并不太大,每条 50 到 300 行左右。 【参考方案1】:

我不知道是否有寻找多字符分隔符的好工具,而且您不是第一个询问它的人。大多数(包括read.tableread.delimreadr::read_delim)都需要单字节分隔符。

一种方法,虽然对于大文件肯定不是有效的,但是以逐行方式加载它们并自己进行分割。

(消耗数据说的最底层。)

x <- readLines(textConnection(file1))
x <- x[x != 'header'] # or x <- x[-(1:5)]

(我猜它并不总是文字 header,所以我假设它要么是固定计数,要么您可以轻松“知道”哪个是哪个。)

spl <- strsplit(x, '   ')
str(spl)
# List of 3
#  $ : chr [1:31] "01130009.JPG" "JPEG" "" "" ...
#  $ : chr [1:20] "01130009.JPG" "JPEG" "" "" ...
#  $ : chr [1:7] "01130009.JPG" "JPEG" "" "" ...

这似乎没问题,只是在你的例子中,右边有很多空白......

spl[[1]]
#  [1] "01130009.JPG"                                                                
#  [2] "JPEG"                                                                        
#  [3] ""                                                                            
#  [4] ""                                                                            
#  [5] "2/5/2018 3:53:44 PM"                                                         
#  [6] "G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg"
#  [7] "Gray Fox"                                                                    
#  [8] ""                                                                            
#  [9] ""                                                                            
# [10] ""                                                                            
# [11] ""                                                                            
# [12] ""                                                                            
# [13] ""                                                                            
# [14] ""                                                                            
# [15] ""                                                                            
# [16] ""                                                                            
# [17] ""                                                                            
# [18] ""                                                                            
# [19] ""                                                                            
# [20] ""                                                                            
# [21] ""                                                                            
# [22] ""                                                                            
# [23] ""                                                                            
# [24] ""                                                                            
# [25] ""                                                                            
# [26] ""                                                                            
# [27] ""                                                                            
# [28] ""                                                                            
# [29] ""                                                                            
# [30] ""                                                                            
# [31] ""                                                                            

因此,如果您知道有多少列,那么您可以轻松删除额外内容:

spl <- lapply(spl, `[`, 1:7)

然后检查输出:

as.data.frame(do.call(rbind, spl), stringsAsFactors = FALSE)
#             V1   V2 V3 V4                  V5
# 1 01130009.JPG JPEG       2/5/2018 3:53:44 PM
# 2 01130009.JPG JPEG       2/5/2018 3:53:44 PM
# 3 01130009.JPG JPEG       2/5/2018 3:53:44 PM
#                                                                             V6
# 1 G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
# 2 G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
# 3 G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
#                                           V7
# 1                                   Gray Fox
# 2 Direct Register Walk, Gait, Gray Fox, Stop
# 3                                   Gray Fox

这同样适用于您的第二个示例:

x <- readLines(textConnection(file2))
x <- x[x != 'header'] # or x <- x[-(1:5)]
spl <- lapply(strsplit(x, '   '), `[`, 1:7)
as.data.frame(do.call(rbind, spl), stringsAsFactors = FALSE)
#             V1   V2 V3 V4                  V5
# 1 01130009.JPG JPEG       2/5/2018 3:53:44 PM
# 2 01130009.JPG JPEG       2/5/2018 3:53:44 PM
# 3 01130009.JPG JPEG       2/5/2018 3:53:44 PM
#                                                                                   V6
# 1 G:\\AAA AAAAAAAA\\AAAAA AA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther DowngBBB
# 2 G:\\AAA AAAAAAAA\\AAAAA AA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther DowngBBB
# 3 G:\\AAA AAAAAAAA\\AAAAA AA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther DowngBBB
#                                           V7
# 1                                   Gray Fox
# 2 Direct Register Walk, Gait, Gray Fox, Stop
# 3                                   Gray Fox

消耗性数据:

# note: replaced single '\' with double '\\' for R string-handling only
file1 <- 'header
header
header
header
header
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg   Gray Fox                                                                           
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg   Direct Register Walk, Gait, Gray Fox, Stop                                         
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg   Gray Fox   '
file2 <- 'header
header
header
header
header
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA AA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther DowngBBB   Gray Fox                                                                           
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA AA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther DowngBBB   Direct Register Walk, Gait, Gray Fox, Stop                                         
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA AA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther DowngBBB   Gray Fox   '

【讨论】:

我尝试了 readLines,并且在那些 txt 文件中存在编码,所以当我执行 readLines 时,我得到“ÿþh”“”“”,而 readLines 不接受 fileEncoding 参数,对吗?我应该修复我的示例,因为这适用于示例数据 readLines(..., encoding="utf-8")? 不,这行不通。我在 Dropbox dropbox.com/s/5st9k602bcfhzwk/first%20one%20-%20Copy.txt?dl=0 中上传了我的 txt 我不知道命令行工具,但我想如果你在传递给 fread 之前将三个空格子放在一个选项卡上,它应该可以工作。 library(data.table); library(magrittr); file2 %&gt;% gsub(" 3(?=[^ ])","\t", ., perl=TRUE) %&gt;% fread(skip=5, fill=TRUE)哦,nvm,刚刚注意到另一个答案涵盖了它。 readLines(file("first one - Copy.txt", encoding='utf-16')) 工作时没有警告/错误。【参考方案2】:

可以读取文件跳过标题行,然后使用gsub函数将3个空格替换为方便的分隔符(此处使用竖线):

> mytext = "01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg   Gray Fox
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg   Direct Register Walk, Gait, Gray Fox, Stop
01130009.JPG   JPEG         2/5/2018 3:53:44 PM   G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg   Gray Fox"

> ddf = read.table(text=gsub("   ", "|", mytext), header=F, sep="|")
> ddf 
            V1   V2 V3 V4                  V5                                                                           V6
1 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
2 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
3 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
                                          V7
1                                   Gray Fox
2 Direct Register Walk, Gait, Gray Fox, Stop
3                                   Gray Fox

编辑:正如下面 cmets 中的@r2evans 所建议的,必须使用gsub(" *$", "", ...) 修剪文本以删除尾随空格。或者,以下函数来自How to trim leading and trailing whitespace in R?:

trim.trailing <- function (x) sub("\\s+$", "", x)

对于文本文件,可以使用 readLines 读取文本文件:

> mytext = readLines(file('testfile.txt')) # read file text
> mytext = mytext[-c(1:5)]           # remove first 5 rows ('header')
> mytext = gsub("\\s+$", "", mytext) # remove trailing spaces
> mytext = gsub("   ", "|", mytext)  # change separator
> ddf = read.table(text=mytext, header=F, sep='|') # read columns from text
> ddf
            V1   V2 V3 V4                  V5                                                                           V6
1 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
2 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
3 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
                                          V7
1                                   Gray Fox
2 Direct Register Walk, Gait, Gray Fox, Stop
3                                   Gray Fox

或者,可以先将它们读取到一个变量的 data.frame 中,然后操作这些行以获得所需的结果:

> ddf1 = read.table(file='testfile.txt', sep = '\n', skip=5)
> mytext = gsub("\\s+$", "", unlist(ddf1$V1))
> ddf2 = read.table(text=gsub("   ", "|", mytext), header=F, sep='|')
> ddf2
            V1   V2 V3 V4                  V5                                                                           V6
1 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
2 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
3 01130009.JPG JPEG NA NA 2/5/2018 3:53:44 PM G:\\AAA AAAAAAAA\\AAAAA\\BBBB BBBB & BBBBB BBBBB\\CAM_07-0008\\Farther Downg
                                          V7
1                                   Gray Fox
2 Direct Register Walk, Gait, Gray Fox, Stop
3                                   Gray Fox

【讨论】:

我认为您的示例数据已从数据中删除了所有尾随空格...我怀疑创建数据文件的任何内容都会填充行。次要,但这意味着read.table 将在每行中看到不同数量的列。 (这可以通过另一个gsub(" *$", "", ...)来缓解。) 为此,我必须打开每个文件并执行 mytext ="...",有没有办法直接从 .txt 读取?我有数百个,我不想打开每一个 @Liza 如果您知道更正分隔符的命令行方法,fread 接受:github.com/Rdatatable/data.table/wiki/… 可以使用read.table函数读取文本文件:astrostatistics.psu.edu/su07/R/html/utils/html/read.table.html

以上是关于读取具有不同列宽但在 R 中固定分隔符的文本文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 CSS 和 HTML 设置在任何设备中固定的文本字符的宽度

R中固定源的置换?

python替换txt文件中固定内容

jQuery 动画位置在 Firefox 中固定不准确

如何在文件中固定数量的字符后插入换行符

R语言使用read.delim函数读取带分隔符的文本文件