Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using reset match token \K with stringr functions

Tags:

regex

r

stringr

I've been answering this Creating a dataframe with text from a website and I have experienced an odd case which I cannot wrap my head around.

We have the lines below copied to our clipboard:

Leading Men (Average American male: 5 feet 9.5 inches)

Dolph Lundgren — 6 feet 5 inches
John Cleese — 6 feet 5 inches

Leading Ladies (Average American female: 5 feet 4 inches)

Uma Thurman — 6 feet 0 inches
Brooke Shields — 6 feet 0 inches

I have provided the solution below, which extracts gender from the header line and fills the following lines/rows with that. The issue here's that it extracts the word 'Leading' as well as "gender". I was expecting to be able to use \K (reset match token) to get rid of that, but that does not work.

web.lines <- read.delim("clipboard", header = F) # reading data from clipboard

library(tidyverse)

web.lines %>% 
  mutate(gender = str_extract(V1, "Leading\\s+\\b(\\w+)\\b")) %>%
  fill(gender , .direction = "down") %>% 
  group_by(gender) %>% 
  slice(-1) %>% # removing the headers
  separate(V1, into = c("Name", "Height"), sep = " — ") 

#> # A tibble: 4 x 3
#> # Groups:   gender [2]
#>    Name                  Height             gender        
#>    <chr>                 <chr>              <chr>         
#> 1  Uma Thurman           6 feet 0 inches    Leading Ladies
#> 2  Brooke Shields        6 feet 0 inches    Leading Ladies
#> 3 Dolph Lundgren         6 feet 5 inches    Leading Men   
#> 4 John Cleese            6 feet 5 inches    Leading Men   

What I have tried was Leading\\s+\\K\\w+ which seems to be working in the demo https://regex101.com/r/pYaW7a/1 but not with str_extract.

like image 986
M-- Avatar asked Jul 18 '26 06:07

M--


1 Answers

You do not need \K in stringr regex functions that do not support it (see the ICU regex syntax documentation), because you have str_match / str_match_all functions.

The \K match reset operator that is supported by PCRE, Perl, Onigmo, Python PyPi regex and Boost regex libraries and thus also available in base R regex functions via perl=TRUE argument, is used to omit some text matched before the current position. The same effect can be achieved with capturing groups. The problem with str_extract and str_extract_all is that they do not keep the captured substrings in the output. str_match/str_match_all keep the captured substrings in their output.

See the R demo:

web.lines %>% 
  mutate(gender = str_match(V1, "Leading\\s+(\\w+)")[,2]) %>%
  fill(gender , .direction = "down") %>% 
  group_by(gender) %>% 
  slice(-1) %>% # removing the headers
  separate(V1, into = c("Name", "Height"), sep = " — ") 

Output:

# A tibble: 4 x 3
# Groups:   gender [2]
  Name           Height          gender
  <chr>          <chr>           <chr> 
1 Uma Thurman    6 feet 0 inches Ladies
2 Brooke Shields 6 feet 0 inches Ladies
3 Dolph Lundgren 6 feet 5 inches Men   
4 John Cleese    6 feet 5 inches Men  

Here, str_match(V1, "Leading\\s+(\\w+)")[,2] is used to match and capture one or more word chars after Leading word and one or more whitespaces, and return just the captured value by accessing the item at the [,2] index.

Note word boundaries are redundant here, there is an implicit word boundary between a whitespace and a word char, and a \b after \w+ is also implicitly present.

like image 155
Wiktor Stribiżew Avatar answered Jul 20 '26 23:07

Wiktor Stribiżew



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!