3

My data contains text messages which look like the below. I want to extract the block age from them.

x:
my block is 8 years old and I am happy with it. I had been travelling since 2 years and that’s fun too…..
He invested in my 1 year block and is happy with the returns
He re-invested in my 1.5 year old block 
i had come to U.K for 4 years and when I reach Germany my block will be of 5 years

I extracted the number followed by the word "year" or "years", But I realised I should be picking the number closer to the word "block".

library(stringr)

> str_extract_all(x, "[0-9.]{1,3}.year|[0-9.]{1,3}.years")
[[1]]
[1] "8 years" "2 years"

[[2]]
[1] "1 year"

[[3]]
[1] "1.5 year"

[[4]]
[1] "4 years" "5 years"

I want the output to be a list containing

8 years
1 year
1.5 year
5 years

I was thinking of extracting part of the sentence which contain the words "block", "old". But I am not quite clear on how to implement this. Any ideas or suggestions to better this process would be helpful.

THANKS

1
  • @David- I want to extract just the age of the block. and I edited my post to include the name of the library Commented Jun 15, 2014 at 11:00

3 Answers 3

3

Here's a solution which keeps using stringr:

library(stringr)
m1 <- str_match(x, "block.*?([0-9.]{1,3}.year[s]?)")
m2 <- str_match(x, "([0-9.]{1,3}.year[s]?).*?block")
sapply(seq_along(x), function(i) {
   if (is.na(m1[i, 1])) m2[i, 2]
   else if (is.na(m2[i, 1])) m1[i, 2]
   else if (str_length(m1[i, 1]) < str_length(m2[i, 1])) m1[i, 2]
   else m2[i, 2]
})
## [1] "8 years"  "1 year"   "1.5 year" "5 years"

Or equivalently:

m1 <- str_match(x, "block.*?([0-9.]{1,3}.year[s]?)")
m2 <- str_match(x, "([0-9.]{1,3}.year[s]?).*?block")
cbind(m1[,2], m2[,2])[cbind(1:nrow(m12), apply(str_length(cbind(m1[,1], m2[,1])), 1, which.min))]

Both solutions assume that "block" appears in each string exactly once.

Sign up to request clarification or add additional context in comments.

1 Comment

I like the idea of str_match. Thanks. :)
0

One idea is to get the position of "blocks" words and "ages". Then for each block compute the nearest age. I am using gregexpr to compute get the position.

## position of blocks
d_block <- unlist(gregexpr('block',txt))
## position of ages
## Note here that I am using ? to simplify your regex
d_age <- unlist(gregexpr("[0-9.]{1,3}.years?",txt))
## for each block , get the nearest age position 
nearest <- sapply(d_block,function(x)d_age[which.min(abs(x-d_age))])
## get ages values
all_ages <- unlist(regmatches(txt,gregexpr("[0-9.]{1,3}.years?",txt)))
## filter to keep only ages near to block
all_ages[d_age %in% nearest]

"8 years"  "1 year"   "1.5 year" "5 years" 

4 Comments

I dont get the same output. I get 8, 4 and 5 years as my output. I am implementing ur code for the same 4 records. > all_ages[d_age %in% nearest] [1] "8 years" "4 years" "5 years"
@user1946217 really?? What do you get when you test over the question text?
i get the below output > all_ages[d_age %in% nearest] [1] "8 years" "4 years" "5 years"
@really amazing you get this !
0

This approach gets the shortest distance "year" or "years" word from a "block", and then removes all the rest of the "year" or "years" in each message before performing your str_extract_all line

goodyear <- lapply(x, function(x) if(length(grep("year",  unlist(strsplit(x, " ")))) > 1) grep("year",  unlist(strsplit(x, " ")))[which.min(abs(grep("block", unlist(strsplit(x, " "))) -  grep("year",  unlist(strsplit(x, " ")))))])
    for(i in seq_len(length(x))){
      if(!is.null(goodyear[[i]])){
        print(str_extract_all(paste(unlist(strsplit(x[[i]], " "))[-setdiff(grep("year",  unlist(strsplit(x[[i]], " "))), goodyear[[i]])], collapse = " "), "[0-9.]{1,3}.year|[0-9.]{1,3}.years"))
      } else print(str_extract_all(x[[i]], "[0-9.]{1,3}.year|[0-9.]{1,3}.years"))
    }

## [[1]]
## [1] "8 years"
##
## [[1]]
## [1] "1 year"
## 
## [[1]]
## [1] "1.5 year"
## 
## [[1]]
## [1] "5 years"

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.