Running regex in R using str_extract_all has regexp not yet implemented - r

I am trying to use regex to parse a file using regex. Most of the solutions to using regex in R use the stringr package. I have not found another way, or another package to use that would work. If you have another way of going about this that would also be acceptable.
What I am trying to accomplish is to grab a couple of values that are seperated by spaces with the last value being some comma seperated values of variable length. This should go into a matrix or df in table like format is it is currently.
foo foo_123bar foo,bar,bazz
foo2 foo_456bar foo2,bar2
I have the working example of my regex here.
There could be a couple of issues I could be running into. The first could be that the regex I am writing is not supported by R's regex engine. Although I have the feeling from this that would be supported. I have seen that R uses a POSIX like format which could make things interesting. The second simply could be exactly what the error message bellow is showing. This is not a feature that has been coded in yet. This however would be the most troubling because I don't know another way to solve my problem without this package.
Below is the R code that I am using to replicate this error
library("stringr")
string = " foo foo_123bar foo,bar,bazz\n foo2 foo_456bar foo2,bar2,bazz2"
pattern = "
(?(DEFINE)
(?<blanks>[[:blank:]]+)
(?<var>\"?[[:alnum:]_]+\"?)
(?<csvar>(\"?[[:alnum:]_]+\"?,?)+)
)
^
(?&blanks)((?&var))
(?&blanks)((?&var))
(?&blanks)((?&csvar))"
# Both of these are throwing the error
str_extract_all(string, pattern)
str_extract_all(string, regex(pattern, multiline=TRUE, comments=TRUE))
> Error in stri_extract_all_regex(string, pattern, simplify = simplify, :
> Use of regexp feature that is not yet implemented. (U_REGEX_UNIMPLEMENTED)
# Using the example from ?str_extract_all runs without error
shopping_list <- c("apples x4", "bag of flour", "bag of sugar", "milk x2")
str_extract_all(shopping_list, "\\b[a-z]+\\b", simplify = TRUE)
I am looking for a solution, not necessarily a stringr solution, but this is the only way I found that fits my needs. The other simpler R regex functions only accept the pattern and not the extra parameters that include the multi line and comment functionality that I am using.

You have a PCRE regex that can only be used in methods/functions that parse the regex with the PCRE regex library (or Boost, it is based on PCRE). stringr str_extract parses the regex with the ICU regex library. ICU regex does not support recursion and DEFINE block. You just can't use the in-pattern approach to define subpatterns and then re-use them.
Instead, just declare the regex parts you need to re-use as variables and build the pattern dynamically:
library("stringr")
string = " foo foo_123bar foo,bar,bazz\n foo2 foo_456bar foo2,bar2,bazz2"
blanks <- "[[:blank:]]+"
vars <- "\"?[[:alnum:]_]+\"?"
csvar <- "(?:\"?[[:alnum:]_]+\"?,?)+"
pattern <- paste0("^",blanks,"(", vars, ")",blanks,"(", vars,")",blanks,"(",csvar, ")")
str_match_all(string, pattern)
# [[1]]
# [,1] [,2] [,3] [,4]
#[1,] " foo foo_123bar foo,bar,bazz" "foo" "foo_123bar" "foo,bar,bazz"
Note: you need to use str_match (or str_match_all) to extract the capturing group values as str_extract or str_extract_all only allows access to the whole match values.

Related

Extract a theme after a dot (in R)

I am trying to extract the theme (DPS3_2h) that is after the dot in:
ABBCCAA.DPS3_2h
Using a below command I am able to extract E15 that before the underscore. Not sure how to do it for the above example.
E15_AAACCCAAGAGGCTGT
types <- sub('(.*)_.*', '\\1', colnames(E15))
If you aren't bound to base R, the stringr package offers a lot of nice functions to work with strings. The pattern used here is using a positive look behind (?<=).
stringr::str_extract("ABBCCAA.DPS3_2h",
pattern = "(?<=\\.).*")
#> [1] "DPS3_2h"

Switching the order of paste() in piping in R

I am fairly new to R and I would like to paste the string "exampletext" in front of each file name within the path.
csvList <- list.files(path = "./csv_by_subject") %>%
paste0("*exampletext")
Currently this code renders things like "csv*exampletext" and I want it to be *exampletextcsv". I would like to continue to using dplyr and piping - help appreciated!
As others pointed out, the pipe is not necessary here. But if you do want to use it, you just have to specify that the second argument to paste0 is "the thing you are piping", which you do using a period (.)
list.files(path = "./csv_by_subject") %>%
paste0("*exampletext", .)
paste0('exampletext', csvList) should do the trick. It's not necessarily using dplyr and piping, but it's taking advantage of the vectorization features that R provides.
If you'd like to paste *exampletext before all of the file names, you can reverse the order of what you're doing now using paste0 and passing the second argument as list.files. paste0 can handle vectors as the second argument and will apply the paste to each element.
csvList <- paste0("*exampletext", list.files(path = "./csv_by_subject"))
This returns a few examples from a local folder on my machine:
csvList
[1] "*exampletext_error_metric.m"
[2] "*exampletext_get_K_clusters.m"
...

Discrepancy between stringr and base R regular expressions

I have this rather annoying to read regular expression.
pattern = "(?<=(?<=[0-9])[dD](?=[0-9]))[0-9]+"
It was generated automatically so human readability or efficiency is less of an issue than validity. It was meant to parse RPG dice type syntax, such as 10d20. Specifically it is supposed to match the 20.
If I use the old method of string matching in R
text = '10d20'
regmatches(text,regexpr(pattern,text,perl = TRUE))
I get what I want, which is 20, however using the more modern method of string matching
stringr::str_match(text, pattern)
I get nothing. I was wondering what causes this difference between the two methods and how can I avoid issues like this in the future.
Unless you need the extras that come with ICU (via stringi which stringr is merely a crutch helper wrapper for) there's no need for woe.
In fact, there's a pkg with less marketing power than tidyverse-based pkgs called stringb which puts "data first" (like string[ir]) and relieves you from base regexp inanity. Vis-a-vis:
library(stringb)
pattern <- "(?<=(?<=[0-9])[dD](?=[0-9]))[0-9]+"
text <- '10d20'
text_extract(text, pattern, perl = TRUE)
## [1] "20"
You get saner syntax without relying on a massive compiled code dependencies and 1-away* stringr abstraction. Bellisimo!
* TBFair: the stringb package also has 1-away abstraction from base R functions but the saner syntax makes up for it IMO (unlike stringr).

Conditional regular expressions in stringr

I'm wondering how to implement a conditional regular expression in R. It seems that this can be implemented in PERL:
?(if)then|else
However, I'm having trouble figuring out how to implement this in R. As a simple example, let's say I have the following strings:
c('abcabd', 'abcabe')
I would like the regular expression to match "bd" if it is there and "bc" otherwise, then replace it with "zz". Thus, I would like the strings above to be:
c('abcazz', 'azzabe')
I have tried this using both sub and str_replace neither of which seem to work. It seems that my syntax might be wrong in sub:
sub('b(?(?=d)d|c)', 'zz', c('abcabe','abcabd'), perl=TRUE)
[1] "azzabe" "azzabd"
The logic is "match b, if followed by d match d, otherwise match c". With str_replace, I get errors :
str_replace(c('abcabe','abcabd'), regex('b(?(?=d)d|c)'), 'zz')
Error in stri_replace_first_regex(string, pattern, fix_replacement(replacement), :
Use of regexp feature that is not yet implemented. (U_REGEX_UNIMPLEMENTED)
I primarily use stringr so would prefer a solution using str_replace but open to solutions using sub.
You are almost near but you should have conditional pattern true assertion in each step:
(?(?=.*bd)bd|bc)
Live demo
You don't even need conditional regex:
^(.*)bd|bc
R code:
sub('^(.*)bd|bc', '\\1zz', c('abcabe','abcabd'))

How to use variable in xpath in R?

when i parse a web file, it works fine ,
tdata=xpathApply(data,"//table[#id='PL']")
i want to use variable in xpathApply,
x="PL"
tdata=xpathApply(data,"//table[#id=x]")
it can not work,how to write the xpath expression in xpathApply with variable?
think for Dason's suggestion,
x="PL"
y=paste0("//table[#id='",x,"']")
tdata=xpathApply(data,y)
it is ok,but i feel it is ugly,how can i write it more beautiful?
The gsubfn package can do string interpolation somewhat along the lines of Perl if we preface the function whose arguments are to contain substitutions with fn$. Here $x means substitute in the value of x . See ?fn and the gsubfn home page.
library(gsubfn)
x <- "PL"
tdata <- fn$xpathApply(data, "//table[#id='$x']")
#Dason's suggestion of using paste or one alike is most likely the only way to go. If you find it ugly, you can sweep it under the rug by creating your own function:
my.xpathApply <- function(data, x) xpathApply(data, paste0("//table[#id='",x,"']"))
tdata <- my.xpathApply(data, "PL")
After all, you must use a lot of package functions that use paste somewhere, so you should be ok with having one of your own :-)

Resources