将不规则文本拆分为表

时间:2016-02-01 22:54:05

标签: r

我的文本表看起来像这样:

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]

但我需要这样做数千次,并且列数和行数不等。

有没有更好的方法来做到这一点,这也适用于任何数量的行?

更新:为了澄清,问题是根据标题和行中空格的位置找到宽度。很抱歉没有明白这一点。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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))