Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use regex to insert space between collapsed words

Tags:

regex

r

gsub

I'm working on a choropleth in R and need to be able to match state names with match.map(). The dataset I'm using sticks multi-word names together, like NorthDakota and DistrictOfColumbia.

How can I use regular expressions to insert a space between lower-upper letter sequences? I've successfully added a space but haven't been able to preserve the letters that indicate where the space goes.

places = c("NorthDakota", "DistrictOfColumbia")
gsub("[[:lower:]][[:upper:]]", " ", places)
[1] "Nort akota"       "Distric  olumbia"
like image 436
Nancy Avatar asked Jul 14 '14 15:07

Nancy


2 Answers

Use parentheses to capture the matched expressions, then \n (\\n in R) to retrieve them:

places = c("NorthDakota", "DistrictOfColumbia")
gsub("([[:lower:]])([[:upper:]])", "\\1 \\2", places)
## [1] "North Dakota"         "District Of Columbia"
like image 132
Ben Bolker Avatar answered Sep 26 '22 12:09

Ben Bolker


You want to use capturing groups to capture to matched context so you can refer back to each matched group in your replacement call. To access the groups, precede two backslashes \\ followed by the group #.

> places = c('NorthDakota', 'DistrictOfColumbia')
> gsub('([[:lower:]])([[:upper:]])', '\\1 \\2', places)
# [1] "North Dakota"         "District Of Columbia"

Another way, switch on PCRE by using perl=T and use lookaround assertions.

> places = c('NorthDakota', 'DistrictOfColumbia')
> gsub('[a-z]\\K(?=[A-Z])', ' ', places, perl=T)
# [1] "North Dakota"         "District Of Columbia"

Explanation:

The \K escape sequence resets the starting point of the reported match and any previously consumed characters are no longer included. Basically ( throws away everything that it has matched up to that point. )

[a-z]       # any character of: 'a' to 'z'
\K          # '\K' (resets the starting point of the reported match)
(?=         # look ahead to see if there is:
  [A-Z]     #   any character of: 'A' to 'Z'
)           # end of look-ahead
like image 41
hwnd Avatar answered Sep 26 '22 12:09

hwnd