Заменить определенные пробелы на вкладки - разделители
У меня есть один столбец 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
По существу, необходимо изменить 1-е, 2-е, 3-е и последнее пространство на вкладку (или любой другой разделитель, если это упростит код).
Игра с regex
еще не дает ничего полезного...
Примечание1: В реальных данных мне нужно заменить 1, 2, 3,..., 19 и последние пробелы на вкладки.
Примечание2: В V4
нет шаблона, текст может быть любым.
Примечание3: Последний столбец - это текст из одного слова с переменной длиной.
Ответы
Ответ 1
Try
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
Ответ 2
С переменным числом столбцов:
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+)
захватить свободный текст из буквенно-цифрового char или пробела [\w ]+
, а затем пробел и захватить последнее слово с помощью \w+
После этого вставьте 3 части, возвращенные str_match
, позаботившись о замене пробелов в первой группе 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 (обратные ссылки)
Ответ 3
Здесь может быть один поворотный способ, который будет работать независимо от количества "слов", которые у вас есть (и это работает с вашими данными); это основано на количестве символов алфавита в ваших "словах" по сравнению с количеством символов алфавита в других полях:
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