读取固定宽度文件,其中列数预先不知道

时间:2014-07-13 21:44:39

标签: r

我正在编写一个函数来读取具有固定宽度格式的文本文件。挑战在于事先不知道列数(它会因文件而异),因此我无法指定widths向量与read.fwf()一起使用。

该文件使用空格作为分隔符,一般格式为: 20个字符,4个字符,3个字符,4个字符,3个字符,...重复一对4字符(空格)3字符(空格)组合,无论需要什么数字。

该文件的示例类似于

Robert De Niro        382 +19 2504  14  346 +16 2445  18 2413 +20 2445  17
Marlon Brando        2427 +13 2495  19 2483 +14 2429  16 2438 +18 2378  20
Martin Scorsese      2501   7  317  +3 2491   1  393  +2 2462   4  394  +9

上面的示例在整个文件中有6对列。其他文件可能有多达33对列。

目前我的工作是预先手动检查每个文件以指定widths值。关于自动化这种方法的任何建议?

2 个答案:

答案 0 :(得分:2)

这是我在Stack Overflow上学到的一个技巧(我的片段说我是从@BenBolker学到的,但我现在无法找到链接),但只有在你的数据是格式的情况下才有效你描述:文字后跟数字。

我们说我们有以下文字:

TEXT <- c(
  "Robert De Niro        382 +19 2504  14  346 +16 2445  18 2413 +20 2445  17",
  "Marlon Brando        2427 +13 2495  19 2483 +14 2429  16 2438 +18 2378  20",
  "Martin Scorsese      2501   7  317  +3 2491   1  393  +2 2462   4  394  +9")

我们可以使用gsub将单词中的空格替换为另一个字符 - 例如下划线或短划线:

gsub(" +([[:alpha:]]+)", "_\\1", TEXT)
# [1] "Robert_De_Niro        382 +19 2504  14  346 +16 2445  18 2413 +20 2445  17"
# [2] "Marlon_Brando        2427 +13 2495  19 2483 +14 2429  16 2438 +18 2378  20"
# [3] "Martin_Scorsese      2501   7  317  +3 2491   1  393  +2 2462   4  394  +9"

这样我们就可以直接使用read.table

read.table(text = gsub(" +([[:alpha:]]+)", "_\\1", text), header = FALSE)
#                V1   V2 V3   V4 V5   V6 V7   V8 V9  V10 V11  V12 V13
# 1  Robert_De_Niro  382 19 2504 14  346 16 2445 18 2413  20 2445  17
# 2   Marlon_Brando 2427 13 2495 19 2483 14 2429 16 2438  18 2378  20
# 3 Martin_Scorsese 2501  7  317  3 2491  1  393  2 2462   4  394   9

正如@BondedDust所提到的,如果你想保留&#34; +&#34;你可以指定colClasses = "character"。在数字之前,但那么你的数字将是字符: - )

答案 1 :(得分:1)

您可以读取最大值然后进行后处理以删除所有NA的所有列:

> read.fwf(textConnection("Robert De Niro        382 +19 2504  14  346 +16 2445  18 2413 +20 2445  17
+ Marlon Brando        2427 +13 2495  19 2483 +14 2429  16 2438 +18 2378  20
+ Martin Scorsese      2501   7  317  +3 2491   1  393  +2 2462   4  394  +9"), widths=c(20, rep(c(5,4), 33) ) )
                    V1   V2 V3   V4 V5   V6 V7   V8 V9  V10 V11  V12 V13 V14
1 Robert De Niro        382 19 2504 14  346 16 2445 18 2413  20 2445  17  NA
2 Marlon Brando        2427 13 2495 19 2483 14 2429 16 2438  18 2378  20  NA
3 Martin Scorsese      2501  7  317  3 2491  1  393  2 2462   4  394   9  NA
  V15 V16 V17 V18 V19 V20 V21 V22 V23 V24 V25 V26 V27 V28 V29 V30 V31 V32 V33
1  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
2  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
3  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
  V34 V35 V36 V37 V38 V39 V40 V41 V42 V43 V44 V45 V46 V47 V48 V49 V50 V51 V52
1  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
2  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
3  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
  V53 V54 V55 V56 V57 V58 V59 V60 V61 V62 V63 V64 V65 V66 V67
1  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
2  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
3  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA

如果您需要保留&#39; +&#39; -signs,请使用colClasses。特别是跟进Ananda的贡献后,这可以作为一个单行使用更灵活的read.table()方法:

 fil <- <insert-file-name-here>
  read.table(text=gsub(" +([[:alpha:]]+)", "_\\1", textConnection( file(fil) ), 
             col.Classes=c("character", "numeric") )

colClasses将根据需要重复多次,因此例如11列文件将被读为:c(&#34;字符&#34;,&#34;数字&#34;,&#34 ;字符&#34;,&#34;数字&#34;,&#34;字符&#34;,&#34;数字&#34;,&#34;字符&#34;,&#34;数字&#34; ,&#34;字符&#34;,&#34;数字&#34;,&#34;字符&#34;)