2016-02-01 30 views
1

我有文本格式的表格看起來像這樣:拆分不規則的文本轉換成表格

in.data <- rbind(
c("ColA KB  Col C The ColE (2.0)"), 
c("abc def  ghijklm n opqrst"), 
c("uv wx y zzzzzz aa bcd"), 
c("ab cd    gh jklmn") 
) 

,我需要它是這樣的:

wanted.result <- rbind(
    c("abc", "def", "ghijklm", "n", "opqrst"), 
    c("uv", "wx y", "zzzzzz", "aa", "bcd"), 
    c("ab", "cd", NA, "gh", "jklmn") 
) 
colnames(wanted.result) <- c("ColA", "KB", "Col C", "The", "ColE (2.0)") 

是什麼讓這個複雜的是,垂直分割符位置可以基於列名和列內容。

這裏是一個醜陋的嘗試的作品:

library(stringr) 
spaces.1 <- unique(unlist(str_locate_all(in.data[1,], " "))) 
spaces.2 <- unique(unlist(str_locate_all(in.data[2,], " "))) 
spaces.3 <- unique(unlist(str_locate_all(in.data[3,], " "))) 
spaces.4 <- unique(unlist(str_locate_all(in.data[4,], " "))) 
spaces.12 <- spaces.1[spaces.1%in%spaces.2] 
spaces.123 <- spaces.12[spaces.12%in%spaces.3] 
spaces.1234 <- spaces.123[spaces.123%in%spaces.4] 
for (i in length(spaces.1234):2) { 
    if (spaces.1234[i]-spaces.1234[i-1]==1) spaces.1234[i] <- NA_integer_ 
} 
delimiters <- na.omit(spaces.1234) 
library(data.table) 
in.data.table <- data.table(in.data) 
in.data.table[, col.1:=substr(V1, start=1, stop=delimiters[1])] 
in.data.table[, col.2:=substr(V1, start=delimiters[1], stop=delimiters[2])] 
in.data.table[, col.3:=substr(V1, start=delimiters[2], stop=delimiters[3])] 
in.data.table[, col.4:=substr(V1, start=delimiters[3], stop=delimiters[4])] 
in.data.table[, col.5:=substr(V1, start=delimiters[4], stop=37)] 
setnames(in.data.table, as.character(in.data.table[1, ])) 
wanted.result.2 <- in.data.table[2:4, 2:6, with=FALSE] 

但我必須這樣做上千次,並伴有不同列和行的數量。

有沒有更好的方法來做到這一點,也適用於任何數量的行?

更新:爲了澄清,問題是根據標題和行中的空格位置查找寬度。對不起,不清楚這一點。

+0

這個過程需要一個規則來確定何時以及有多少NA值來填寫。 –

+0

這不僅僅是一個固定寬度的文本文件嗎? - 例如 - ''read.fwf'應該能夠應付它。 – thelatemail

+0

我認爲read.fwf需要寬度,這些寬度在我的數據中是事先不知道的。 – Chris

回答

2

我們假設一個包含所有行的空間,任何列分隔字段,我們假設最後一個字段的寬度爲10或更小(如果需要,更改此數字)。沒有包被使用。

w <- diff(Reduce(intersect, gregexpr(" ", paste("", in.data)))) 
w <- c(w, 10) 
X <- read.fwf(textConnection(in.data), w, skip = 1, as.is = TRUE) 
names(X) <- trimws(read.fwf(textConnection(in.data), w, n = 1, as.is = TRUE)) 
X <- X[names(X) != "NA"] 
X[] <- lapply(X, trimws) 

,並提供:

> X 
    ColA ColB Col C ColD ColE (2.0) 
1 abc def ghijklm n  opqrst 
2 uv wx y zzzzzz aa  bcd 
3 ab cd   gh  jklmn 

注:我們用這個在上面的測試運行中輸入:

in.data <- 
structure(c("ColA ColB Col C ColD ColE (2.0)", "abc def  ghijklm n opqrst", 
"uv wx y zzzzzz aa bcd", "ab cd    gh jklmn" 
), .Dim = c(4L, 1L)) 
2

使用read.fwf使用gregexpr呼叫搞清楚列寬尋找的東西,它定義的列名之後:

txt <- paste(c(in.data),collapse="\n") 
widths <- diff(c(gregexpr("Col", in.data[1])[[1]], nchar(in.data[1])+1)) 
out <- read.fwf(textConnection(txt), widths=widths, skip=1) 
names(out) <- unlist(read.fwf(textConnection(txt), widths=widths, n=1)) 
out 

# ColA ColB  Col C  ColD ColE (2.0) 
#1 abc def  ghijklm n   opqrst 
#2 uv wx y zzzzzz aa   bcd 
#3 ab cd     gh   jklmn 
+0

對不起,我應該提到並非所有的列名都以col開頭。我將在示例中改變這一點。 – Chris

+0

@Chris - 好的,如果沒有明確的規則來定義列,你將不得不手動獲取寬度。沒有任何計劃可以成爲心靈讀者。 – thelatemail