将某些空格替换为制表符 - 分隔符
Replace certain spaces to tabs - delimiters
我有一列 data.frame
,其中一些 space 应该是定界符,有些只是 space.
#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
基本上,需要将第一个、第二个、第三个和最后一个 space 更改为制表符(或任何其他分隔符,如果这样更容易编码)。
玩 regex
还没有提供任何有用的东西...
注意 1: 在实际数据中,我必须将第 1、2、3、...、19 和最后 space 替换为制表符。
注意2:V4
没有模式,文本可以是任何东西。
注3:最后一列是可变长度的一个单词文本。
尝试
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 启发的选项 post
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
这可能是一种扭曲的方式,无论您有多少 "words" 都可以使用(并且可以处理您的数据);它基于您 "words" 中字母数字字符的数量与其他字段中字母数字字符数量的比较:
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
列数可变:
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})
捕获非捕获组 (?:\w+ )
的 3 次重复 {3}
匹配至少一个字母数字字符 w+
后跟 space
([\w ]+) (\w+)
从字母数字字符或 space [\w ]+
后跟 space 捕获自由文本,并用 \w+
[= 捕获最后一个词40=]
完成后,粘贴 str_match
返回的 3 个部分,注意用制表符替换第一组 m[,2]
中的 space。
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(向后引用)加多少就加多少
我有一列 data.frame
,其中一些 space 应该是定界符,有些只是 space.
#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
基本上,需要将第一个、第二个、第三个和最后一个 space 更改为制表符(或任何其他分隔符,如果这样更容易编码)。
玩 regex
还没有提供任何有用的东西...
注意 1: 在实际数据中,我必须将第 1、2、3、...、19 和最后 space 替换为制表符。
注意2:V4
没有模式,文本可以是任何东西。
注3:最后一列是可变长度的一个单词文本。
尝试
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 启发的选项 post
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
这可能是一种扭曲的方式,无论您有多少 "words" 都可以使用(并且可以处理您的数据);它基于您 "words" 中字母数字字符的数量与其他字段中字母数字字符数量的比较:
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
列数可变:
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})
捕获非捕获组(?:\w+ )
的 3 次重复{3}
匹配至少一个字母数字字符w+
后跟 space([\w ]+) (\w+)
从字母数字字符或 space[\w ]+
后跟 space 捕获自由文本,并用\w+
[= 捕获最后一个词40=]
完成后,粘贴 str_match
返回的 3 个部分,注意用制表符替换第一组 m[,2]
中的 space。
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(向后引用)加多少就加多少