How to search for patterns that are not exactly same each time?
I have a list like this:
list <- c("xxx 23 cut", "yyy", "zzz", "www 55 cut", "kkk", "ggg", "yyy", "eee 7 cut", "ccd" )
The searching patter in this case is "any-number cut". Thus, to visualize the list in a better way, the list is in the following pattern
"before item (=xxx) " "any number cut (= 23 cut)"
"after item (=yyy)"
"after item (=zzz)"
"before item (=www) " "any number cut (= 55 cut)"
"after item (=kkk)"
"after item (=ggg)"
"after items (=yyy)"
"before item (=eee) " "any number cut (= 7cut)"
"after item (=cce)"
I want place the "before items" to column 1, until it found another "any number cut" pattern, and put the "after items" to column 2. The final results would as follows:
xxx yyy
xxx zzz
www kkk
www ggg
www yyy
eee ccd
Could experts teach me how to do it with R? I learn from previous stackoverflow messages that R can search for fixed items (e.g. cut) and strsplit them into different cells. The challenge here (to me) is the searching pattern is changing that the number before开发者_StackOverflow the word "cut" is different for each of them. what is the most efficient way to search and cut it in the right place using R?
The following works with your example data:
x <- c("xxx 23 cut", "yyy", "zzz", "www 55 cut", "kkk", "ggg", "yyy", "eee 7 cut", "ccd" )
First, create a regex
pattern to use with grep
: The following pattern searches for digits (\d) followed by a space and the word cut. See ?regexp
and ?grep
for details.
cut_pattern <- "\\d* cut"
cut_positions <- grep(cut_pattern, x)
cut_repeat <- c(cut_positions[-1], length(x) + 1) - cut_positions -1
before_items <- rep(x[cut_positions], times=cut_repeat)
after_items <- x[!grepl(cut_pattern, x)]
data.frame(
before = before_items,
after = after_items
)
The results:
before after
1 xxx 23 cut yyy
2 xxx 23 cut zzz
3 www 55 cut kkk
4 www 55 cut ggg
5 www 55 cut yyy
6 eee 7 cut ccd
I will leave it as an exercise to you to do the cleanup of the data in column 1. Hint: Use str_extract
in package stringr
. You can refer to this question: How can I use back references with `grep` in R? for examples of how to do this. Further hint, your patterns should be something like "(.*) \\d* cut"
.
Below we use x
to represent your list
variable. " \d+ cut$" matches any string with space, digits, space and cut at the end so that no.cut
is a logical vector that is TRUE for each component of x with no cut. We then pick out the first word of each component by removing the first space and everything after it. This gives first.word
. Finally we replace each component of first.word
with NA
if it has no cut and use na.locf
from the zoo package to move the remaining words (the ones that were not replaced by NA
) forward into the NA spots to give us the tentative before
vector. We use first.word
as the tentative after
vector. The positions corresponding to no.cut
in the tentative before
and after
vectors form the required result. This works with your example data. Depending on the precise nature of your actual data you may need to revise some of this slightly; however, the overall pattern of the solution should still hold.
> library(zoo)
> no.cut <- !grepl(" \\d+ cut$", x)
> first.word <- sub(" .*", "", x)
> cbind(before = na.locf(replace(first.word, no.cut, NA)),
+ after = first.word)[no.cut, ]
before after
[1,] "xxx" "yyy"
[2,] "xxx" "zzz"
[3,] "www" "kkk"
[4,] "www" "ggg"
[5,] "www" "yyy"
[6,] "eee" "ccd"
精彩评论