2014-07-13 67 views
0

我正在寫一個函數來讀取固定寬度格式的文本文件。我們面臨的挑戰是列的數量並不是事先知道的(它會因文件而異),所以我不能指定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值。任何可能的方法來自動化這個建議?

+0

你可以使用'readLines(...,n = 3)讀取文件的前幾行。然後,您可以嘗試基於此做出決定。我想不出一種可以在任何情況下都能正常工作的算法,所以這取決於這些文件如何相似以確定中斷應該在哪裏。如果唯一認爲可變的是4/3對的數量,則應該可以通過第一行中的字符數來判斷。 – MrFlick

+0

我看不出有什麼理由爲什麼'read.table'不起作用。它忽略了多餘的空白。 –

+0

@BonddedDust問題是名稱中的空格,不是? – MrFlick

回答

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提到,如果你想在數字前面加「+」,你可以指定colClasses = "character",但是你的數字將會是字符:-)

+0

謝謝,這很聰明。不幸的是,我確實需要保留「+」,所以我猜它現在不再是文字,而是數字。 – Ricky

+0

@瑞奇,我想你誤會了。你應該仍然可以使用這種方法,但是從列「V2」到「V13」(在這個例子中)將是字符,所以你不能說'總結'它們。 – A5C1D2H2I1M1N2O1R2T1

+0

啊我看到了,傻了。我會試一試。 – Ricky

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 

使用colClasses - 跡象。特別是跟進阿難的貢獻,這可能使用更靈活的函數read.table一個班輪工作()方法:根據需要

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

的colClasses將得到重複多次,所以例如11-列文件wold讀取爲:c(「字符」,「數字」,「字符」,「數字」,「字符」,「數字」,「字符」,「數字」,「字符」,「數字」字符「)

+0

感謝你們,不幸的是,我剛剛遇到了一個帶有45對4 + 3列的文件,所以我不再相信最大數量的配對。 – Ricky

+0

我沒有看到,發現您向我們建議的例外情況是最大大小會將此視爲策略失效。 –

+0

我可能誤解了「讀到最大」部分;我認爲最大需要被知道,在這個解決方案中'widths = c(20,rep(c(5,4),33))' 現在我沒有知道最大值(它可能不是45,只是現在我發現了33以上的東西,我不認爲33是一個安全的數字),我不確定用什麼來代替上面的33。 – Ricky