2015-06-23 5 views
10

У меня есть одна колонка 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 не дает ничего полезного пока ...

Note1: В реальных данных я должен заменить 1-й, 2-й, 3-й, ..., 19 и последние пробелы в закладках.
Примечание2: Нет рисунка в V4, текст может быть любым.
Note3: Последняя колонка - это текст одного слова с переменной длиной.

+2

Попробуйте 'v1 <- gsub ("^([^] +) \\ s + ([^] +) \\ s + ([^] +) \\ s + ", '\\ 1 , \\ 2, \\ 3, ', dt $ x); read.table (text = sub (' + (? = [^] + $) ',', ', V1, perl = TRUE), sep = ",") ' – akrun

+0

Спасибо @akrun, пожалуйста, добавьте свой комментарий как ответ. – zx8754

+0

@akrun см. Примечание. Ваше решение все равно будет работать, просто нужно перейти к '' \\ 1, \\ 2, ... \\\ 19 '... ' – zx8754

ответ

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

Извините, я не могу дважды удвоить, редактировать (у меня не было идеи сделать шаблон внутри функции, и вызов gsub, чтобы воспользоваться цитированной интерпретацией read.table, замечательно) Мне все еще нужно учиться – Tensibai

+1

@Tensibai Редактирование возможно только потому, что вашего умного кода. Некоторое время я размышлял, но не понял. Спасибо за поддержку. – akrun

3

Здесь может быть один искривленный путь, который будет работать независимо количество «слов», которое у вас есть (и что работает с вашими данными); она основана на количестве alphanum символов в ваших «слова» по сравнению с количеством alphanum символов в других областях:

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 

EDIT: Совершенно другой путь, только на основе численности пространства 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 
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+

как только это сделано, вставьте 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 (обратные ссылки)

Смежные вопросы