将某些空格替换为制表符 - 分隔符

时间:2015-06-23 12:34:06

标签: regex r dataframe delimiter

我有一列data.frame,其中一些空格应该是分隔符,有些只是空格。

#input data
dat <- data.frame(x=c("A 2 2 textA1 textA2 Z1",
                      "B 4 1 textX1 textX2 textX3 Z2",
                      "C 3 5 textA1 Z3"))
#                               x
# 1        A 2 2 textA1 textA2 Z1
# 2 B 4 1 textX1 textX2 textX3 Z2
# 3               C 3 5 textA1 Z3

需要将其转换为5列data.frame

#expected output
output <- read.table(text="
A   2   2   textA1 textA2   Z1
B   4   1   textX1 textX2 textX3    Z2
C   3   5   textA1  Z3",sep="\t")
#   V1 V2 V3                   V4 V5
# 1  A  2  2        textA1 textA2 Z1
# 2  B  4  1 textX1 textX2 textX3 Z2
# 3  C  3  5               textA1 Z3

基本上,需要将第一个,第二个,第三个和最后一个空格更改为选项卡(或任何其他分隔符,如果它更容易编码)。

regex并没有给出任何有用的东西......

注1:在实际数据中,我必须将第1,第2,第3,......,第19和最后一个空格替换为标签。
注2: V4中没有模式,文字可以是任何内容 注3:最后一列是一个可变长度的单词文字。

3 个答案:

答案 0 :(得分:8)

尝试

v1 <- gsub("^([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+", '\\1,\\2,\\3,', dat$x)
read.table(text=sub(' +(?=[^ ]+$)', ',', v1, perl=TRUE), sep=",")
#  V1 V2 V3                   V4 V5
#1  A  2  2        textA1 textA2 Z1
#2  B  4  1 textX1 textX2 textX3 Z2
#3  C  3  5               textA1 Z3

或者选择灵感来自@ Tensibai的帖子

n <- 3
fpat <- function(n){
   paste0('^((?:\\w+ ){', n,'})([\\w ]+)\\s+(\\w+)$')
}

read.table(text=gsub(fpat(n), "\\1'\\2' \\3", dat$x, perl=TRUE))
#  V1 V2 V3                   V4 V5
#1  A  2  2        textA1 textA2 Z1
#2  B  4  1 textX1 textX2 textX3 Z2
#3  C  3  5               textA1 Z3

有关更多列,

 n <- 19
 v1 <- "A 24 34343 212 zea4 2323 12343 111 dsds 134d 153xd 153xe 153de 153dd dd dees eese tees3 zee2 2353 23335 23353 ddfe 3133"

 read.table(text=gsub(fpat(n), "\\1'\\2' \\3", v1, perl=TRUE), sep='')
 # V1 V2    V3  V4   V5   V6    V7  V8   V9  V10   V11   V12   V13   V14 V15
 #1  A 24 34343 212 zea4 2323 12343 111 dsds 134d 153xd 153xe 153de 153dd  dd
 #  V16  V17   V18  V19                   V20  V21
 #1 dees eese tees3 zee2 2353 23335 23353 ddfe 3133

答案 1 :(得分:6)

列数可变:

library(stringr)
cols <- 3
m <- str_match(dat$x, paste0("((?:\\w+ ){" , cols , "})([\\w ]+) (\\w+)"))
t <- paste0(gsub(" ", "\t", m[,2]), m[,3], "\t", m[,4])

> read.table(text=t,sep="\t")
  V1 V2 V3                   V4 V5
1  A  2  2        textA1 textA2 Z1
2  B  4  1 textX1 textX2 textX3 Z2
3  C  3  5               textA1 Z3

更改列数以告知您之前的数量。 对于正则表达式:

  • ((?:\\w+ ){3})捕获非捕获组{3}的3个重复(?:\w+ ),其中至少有一个字母数字字符w+,后跟一个空格
  • ([\\w ]+) (\w+)从字母数字字符或空格[\w ]+中捕获自由文本,后跟空格,然后使用\w+
  • 捕获最后一个字词

完成后,粘贴由str_match返回的3个部分,负责通过标签替换第一组m[,2]中的空格。

m[,1]是完整的匹配,因此在这里未使用。

旧答案:

基于固定数量的字段的基本匹配:

> read.table(text=gsub("(\\w+) (\\w+) (\\w+) ([\\w ]+) (\\w+)$","\\1\t\\2\t\\3\t\\4\t\\5",dat$x,perl=TRUE),sep="\t")
  V1 V2 V3                   V4 V5
1  A  2  2        textA1 textA2 Z1
2  B  4  1 textX1 textX2 textX3 Z2
3  C  3  5               textA1 Z3

添加你想要的数量(\ w +),并增加\ 1(反向引用)的数量

答案 2 :(得分:3)

这可能是一种扭曲的方式,无论多少&#34;单词&#34;你有(并且适用于你的数据);它是基于你的&#34;单词&#34;中的字母数字的数量。与其他字段中的字母数字相比:

res <- gsub("\\w{3,}\\K\\t(?=\\w{3,})", " ", gsub(" ", "\t", dat$x), perl=T)
res
# [1] "A\t2\t2\ttextA1 textA2\tZ1"        "B\t4\t1\ttextX1 textX2 textX3\tZ2" "C\t3\t5\ttextA1\tZ3"

read.table(text=res, sep="\t")
#  V1 V2 V3                   V4 V5
#1  A  2  2        textA1 textA2 Z1
#2  B  4  1 textX1 textX2 textX3 Z2
#3  C  3  5               textA1 Z3

编辑:完全不同的方式,仅基于您需要在最后一个之前替换的空格k的数量:

k <- 3 # in your example
res <- sapply(as.character(dat$x), 
              function(x, k){
                 pos_sp <- gregexpr(" ", x)[[1]]
                 x <- strsplit(x, "")[[1]]
                 if (length(pos_sp) > k+1) pos_sp <- pos_sp[c(1:k, length(pos_sp))]
                 x[pos_sp] <- "\t"
                 x <- paste(x, collapse="")
               }, k=k)

read.table(text=res, sep="\t")
#   V1 V2 V3                   V4 V5
# 1  A  2  2        textA1 textA2 Z1
# 2  B  4  1 textX1 textX2 textX3 Z2
# 3  C  3  5               textA1 Z3