How to extract a specific instance of a string of digits after a specific character using regex

Viewed 100

Title may be confusing, so allow me to elaborate, say I have initialized the following strings

some_string_1 <- "Charges: $400.50 applied to account 1, $300.70 applied to account 2, $120.30 applied to account 3"

some_string_2 <- "Charges: $500.50 applied to account 2, $200.10 applied to account 3, $150.90 applied to account 1"

Lets say I am only focusing on account 1, so I want to extract to numbers after the dollar sign associated with the charge on account 1. I want to know how, using regex and functions like str_extract, I can get the following outputs:

Suppose I call str_extract(some_string_1, regexp), I would like it to give

[1] "400.50"

And suppose I call str_extract(some_string_2, regexp), I would like it to give

[1] "150.90"

As you can see, the charge applied to account 1 is in different places in both strings (it is the first charge listed in string 1 but the third one in string 2), so the regular expression has to account for this.

So far all I have is the following: regexp <- "(?<=\\$)\\d+(?=.)", which successfully gives me the number after the first dollar sign that appears in the string (without the digits in the decimal place that is), but I have no idea how to specify that I only want the number after the dollar sign that is associated with the charge applied on account 1. Looking for help on this aspect.

4 Answers

Not really a regex answer that you are looking for -

vec <- c(some_string_1, some_string_2)

sapply(strsplit(vec, ',\\s*'), function(x) 
  sub('.*\\$(\\d+\\.\\d+).*', '\\1', x[grep('account 1', x)]))

#[1] "400.50" "150.90"

Logic here is to split every account as separate vectors and extract number from 'account 1'.

Here is one solution to your problem. I do not use r so I can not provide you with any code.


Regex

(\$\d+(?:\.\d+)?)[^,\"]*account [#{range}]

where the #{range} can be 1-1, 2-3 and so on. The part you are interested in will be obtained in group 1 of the match. Please note the regex must be applied globally to find all the matches.


Output

#{range} = 1-1

match 1:                                 match 2:
$400.50 applied to account 1             $150.90 applied to account 1
group-1:                                 group-1:
$400.50                                  $150.90


#{range} = 2-3

match 1:                                 match 2:
$300.70 applied to account 2             $120.30 applied to account 3
group-1:                                 group-1:
$300.70                                  $120.30

match 3:                                 match 4:
$500.50 applied to account 2             $200.10 applied to account 3
group-1:                                 group-1:
$500.50                                  $200.10

Test Link: https://regex101.com/r/w3VY4I/1


Please do comment if you are facing any further problems.

You may also convert these strings into a nicely arranged data, using the following strategy

library(tidyverse)

some_string_1 <- "Charges: $400.50 applied to account 1, $300.70 applied to account 2, $120.30 applied to account 3"

some_string_2 <- "Charges: $500.50 applied to account 2, $200.10 applied to account 3, $150.90 applied to account 1"

c(some_string_1, some_string_2) %>% as.data.frame() %>%
  setNames('Strings') %>%
  mutate(ID = row_number()) %>%
  separate_rows(Strings, sep = ', ') %>%
  extract(Strings, into = c('Amt', 'Account'), regex = '\\$(\\d+\\.\\d*).*(account \\d+)') %>%
  pivot_wider(names_from = Account, values_from = Amt)

#> # A tibble: 2 x 4
#>      ID `account 1` `account 2` `account 3`
#>   <int> <chr>       <chr>       <chr>      
#> 1     1 400.50      300.70      120.30     
#> 2     2 150.90      500.50      200.10

Using values_fn = as.numeric argument in pivot_wider will simultaneously convert character values into numeric, which may be useful for further analysis.

A way using only stringr::str_extract might be:

stringr::str_extract(some_string_1, "(?<=\\$)\\d*\\.?\\d*(?=[^$]*account 1)")
#[1] "400.50"

stringr::str_extract(some_string_2, "(?<=\\$)\\d*\\.?\\d*(?=[^$]*account 1)")
#[1] "150.90"
Related