substring() with () in the vector

Viewed 82

I'd like to break this column into 2, using the first bracket as the separater. I used word(x,2, sep = "(") but I got an error. I understand that R doesn't like brackets as sep. I want to use "(" as a sep because the data is not consistently recorded, on some rows, we have a space between the country and the state, on some other rows we don't.

How do I get around this? Thank you.

x <- c("United States (Alabama) ", "United States (California) ", 
"United States (California) ", "United States (California) ", 
"United States (California) ", "United States (Colorado) ", 
"United States (Colorado) ", "United States (Colorado) ", 
"United States(Connecticut) ", "United States(Connecticut) "
)
word(x,2,sep = "("). 

Error in stri_locate_all_regex(string, pattern, omit_no_match = TRUE, : Incorrectly nested parentheses in regexp pattern. (U_REGEX_MISMATCHED_PAREN, context=()

4 Answers

I guess you can try strsplit + gsub like below

trimws(
  gsub(
    "\\(|\\)",
    "",
    do.call(
      rbind,
      strsplit(x,
        "((?<=\\s)\\()|(?=)\\(",
        perl = TRUE
      )
    )
  )
)

which gives

      [,1]            [,2]
 [1,] "United States" "Alabama"
 [2,] "United States" "California"
 [3,] "United States" "California"
 [4,] "United States" "California" 
 [5,] "United States" "California"
 [6,] "United States" "Colorado"
 [7,] "United States" "Colorado"
 [8,] "United States" "Colorado"
 [9,] "United States" "Connecticut"
[10,] "United States" "Connecticut"

Here is a sub/scan approach.

matrix(trimws(scan(what = character(), text = sub("\\)", "", x), sep = "(")), ncol = 2, byrow = TRUE)
#Read 20 items
#      [,1]            [,2]         
# [1,] "United States" "Alabama"    
# [2,] "United States" "California" 
# [3,] "United States" "California" 
# [4,] "United States" "California" 
# [5,] "United States" "California" 
# [6,] "United States" "Colorado"   
# [7,] "United States" "Colorado"   
# [8,] "United States" "Colorado"   
# [9,] "United States" "Connecticut"
#[10,] "United States" "Connecticut"

Explanation

The code above uses scan to break each string in two by a sep character. Since the sep must have length 1, choose one of "(" or ")". I have chosen "(", so before, remove the other one, ")", with sub. The rest is straightforward.

The instructions sequence is:

tmp <- sub("\\)", "", x)
tmp <- scan(what = character(), text = tmp, sep = "(")
tmp <- trimws(tmp)
matrix(tmp, ncol = 2, byrow = TRUE)

I'm assuming you're using stringr::word? If so, the sep argument is interpreted as a regular expression. You could either escape the '(' like this:

word(x, 2, sep = "\\(")

or you can use the fixed function:

word(x, 2, sep = fixed("("))

Another approach is to use this regex \(([^\)]+)\), which will capture the state (assuming that is what you are after).

library(gsubfn)
strapplyc(x = df, pattern = "\(([^\)]+)\)")

Which yields the list

[1] "Alabama"

[[2]]
[1] "California"

[[3]]
[1] "California"

[[4]]
[1] "California"

[[5]]
[1] "California"

[[6]]
[1] "Colorado"

[[7]]
[1] "Colorado"

[[8]]
[1] "Colorado"

[[9]]
[1] "Connecticut"

[[10]]
[1] "Connecticut"
Related