2016-05-25 3 views
1

У меня есть таблица с полем символов, который может иметь любой из этой схемы:Spliting строка с конкретным шаблоном

input    

97     # a single number 
210 foo   # a number and a word 
87 bar 89   # a number, a word, a number 
21 23    # two numbers 
123 2 fizzbuzz  # two number, a word   
12 fizz 34 buzz # a number, a word, a number, a word 

я хотел бы разделить каждую линию до 4-х частей, содержащая соответственно the first number, the first word если есть, the second number если есть, и the second word если есть. Так что мой пример даст:

input    nb_1 word_1 nb_2 word_2 

97     97 
210 foo    210  foo 
87 bar 89   87  bar  89 
21 23    21    23 
123 2 fizzbuzz  123    2  fizzbuzz 
12 fizz 34 buzz  12  fizz  34  buzz 

Пожалуйста, обратите внимание на случай two number, a word (пример до последнего): это не имеет ничего word_1 как нет ни слова между двумя числами.

Есть ли способ сделать это без утомительной структуры if/if/else?

Если это может помочь, все слова принадлежат к списку из 10 конкретных слов. Кроме того, если есть два слова, они могут быть одинаковыми или разными. Кроме того, цифры могут составлять одну, две или три цифры.

Благодаря

+2

Для показа примера используйте 'dput'. Является ли это одной строкой или двумя столбцами в data.frame, т. Е. '« Один номер: 97 »' – akrun

+0

Извините, это было просто указание шаблона, я изменил вопрос в надежде более ясным образом. –

ответ

1

Вот идея, используя gsub и cSplit от splitstackshape пакета,

library(splitstackshape) 
df$num <- gsub('\\D', ' ', df$V1) 
df$wrds <- gsub('\\d', ' ', df$V1) 
newdf <- cSplit(df, 2:3, ' ', 'wide') 
newdf 
#         V1 num_1 num_2 wrds_1 wrds_2 
#1:         97 97 NA  NA  NA 
#2:        210 foo 210 NA  foo  NA 
#3:       87 bar 89 87 89  bar  NA 
#4:        21 23 21 23  NA  NA 
#5:      123 2 fizzbuzz 123  2 fizzbuzz  NA 
#6:      12 fizz 34 buzz 12 34  fizz buzz 

Единственная проблема состоит в строке 5, которая может быть определена следующим образом,

newdf$wrds_1 <- as.character(newdf$wrds_1) 
newdf$wrds_2 <- as.character(newdf$wrds_2) 
newdf$wrds_2[grep('[0-9]+\\s+[0-9]+\\s+[A-Za-z]', newdf$V1)] <- newdf$wrds_1[grep('[0-9]+\\s+[0-9]+\\s+[A-Za-z]', newdf$V1)] 
newdf$wrds_1[grep('[0-9]+\\s+[0-9]+\\s+[A-Za-z]', newdf$V1)] <- NA 

, который наконец, дает,

newdf 
#         V1 num_1 num_2 wrds_1 wrds_2 
#1:         97 97 NA  NA  NA 
#2:        210 foo 210 NA foo  NA 
#3:       87 bar 89 87 89 bar  NA 
#4:        21 23 21 23  NA  NA 
#5:      123 2 fizzbuzz 123  2  NA fizzbuzz 
#6:      12 fizz 34 buzz 12 34 fizz  buzz 

DATA

dput(df) 
structure(list(V1 = c("97", "     210 foo", "       87 bar 89", 
"     21 23", "     123 2 fizzbuzz", 
"     12 fizz 34 buzz")), .Names = "V1", row.names = c(NA, 
-6L), class = "data.frame") 
+0

Спасибо за все три ответа, пошел с этим, как мне показалось, чем проще. –

1
Tried in a different way... 
library(splitstackshape) 
    abc <- data.frame(a=c(97,"210 foo","87 bar 89","21 23","123 2 fizzbuzz","12 fizz 34 buzz")) 
    abc1 <- data.frame(cSplit(abc, "a", " ", stripWhite = FALSE)) 
    abc <- cbind(abc,abc1) 
    names(abc) <- c("input","nb_1", "word_1", "nb_2","word_2") 
    abc[,1:5] <-apply(abc[,1:5] , 2, as.character) 
    for(i in 1:nrow(abc)){ 
     abc$word_2[i] <- replace(abc$word_2[i] , is.na(abc$word_2[i]),abc$nb_2[grepl("[a-z]",abc$nb_2[i])][i]) 
     abc$nb_2[i] <- replace(abc$nb_2[i] , is.na(abc$nb_2[i])|grepl("[a-z]",abc$nb_2[i]),abc$word_1[grepl("[0-9]",abc$word_1[i])][i]) 
     } 
    abc$word_1 <- ifelse(grepl("[0-9]",abc$word_1),NA,abc$word_1) 
    abc[is.na(abc)] <- "" 
    print(abc) 
      input nb_1 word_1 nb_2 word_2 
1    97 97      
2   210 foo 210 foo    
3  87 bar 89 87 bar 89   
4   21 23 21   23   
5 123 2 fizzbuzz 123   2 fizzbuzz 
6 12 fizz 34 buzz 12 fizz 34  buzz 
+0

Пожалуйста, добавьте свои комментарии, если мой подход неверен –

1

Это Hacky функция, чтобы сделать это ... хотя вы, возможно, есть и другие случаи, которые нарушают его.

f <- function(x){ 
    string2 <- strsplit(x, " ")[[1]] 
    if (length(string2) < 2) 
    return(c(string2, NA, NA, NA)) 
    arenums <- grepl("\\d", string2) 
    c(string2[which(arenums)[1]], 
    if (arenums[2]) NA else string2[which(!arenums)[1]],  
    string2[which(arenums)[2]], 
    if (arenums[2]) string2[which(!arenums)[1]] else string2[which(!arenums)[2]]) 
} 

> f("97") 
[1] "97" NA NA NA 
> f("210 foo") 
[1] "210" "foo" NA NA 
> f("87 bar 89") 
[1] "87" "bar" "89" NA 
> f("21 23") 
[1] "21" NA "23" NA 
> f("123 2 fizzbuzz") 
[1] "123"  NA   "2"  "fizzbuzz" 
> f("12 fizz 34 buzz") 
[1] "12" "fizz" "34" "buzz"