Here's a reproducible example
S0 <- "\n3 4 5"
S1 <- "\n3 5"
I want to use gsub and the following regex pattern (outside of R it works - tested in regex101) to return the digits. This regex should ignore \ and n whether they occur together or not.
([^\\n])(\s{1})?
I am not looking for a way to match the digits with a fundamentally different pattern - I'd like to know how to get the above pattern to work in R. The following do not work for me
gsub("([^\\\n])(\\s{1})?", "\\1", S0)
gsub("([^[\\\]n])(\\s{1})?", "\\1", S1)
The output should be
#S0 - 345
#S1 - 3 5
Since you specifically want that regex to work you could match and optional \n (using (\n)?):
gsub("(\n)?([^\\n])(\\s{1})", "\\2", S0)
#[1] "345"
gsub("(\n)?([^\\n])(\\s{1})", "\\2", S1)
#[1] "3 5"
Note that you were right, if you use a regex tester like: https://regex101.com/ it works without the extra "(\n)?". However, I think in R you have to match more for capture groups to work properly.
Your ([^\\n])(\s{1})? pattern in regex101 (PCRE) matches different strings than the same pattern used in gsub without perl=TRUE (that is, when it is handled by the TRE regex library). They would work the same if you used perl=TRUE and use gsub("([^\\\\n])(\\s{1})?", "\\1", S1, perl=TRUE).
What is so peculair with the PCRE Regex ([^\\n])(\s{1})?
This pattern in a regex tester with PCRE option matches:
([^\\n]) - any char other than \ and n (put into Group 1)
(\s{1})? - matches and captures into Group 2 any single whitespace char, optionally, 1 or 0 times.
Note this pattern does not match any non-newline char with the first capturing group, it would match any non-newline if it were [^\n].
Now, the same regex with gsub will be
gsub("([^\n])(\\s{1})?", "\\1", S1) # OR
gsub("([^\\\\n])(\\s{1})?", "\\1", S1, perl=TRUE)
Why different number of backslashes? Because the first regex is handled with TRE regex library and in these patterns, inside bracket expressions, no regex escapes are parsed as such, the \ and n are treated as 2 separate chars. In a PCRE pattern, the one with perl=TRUE, the [...] are called character classes and inside them, you can define regex escapes, and thus the \ regex escape char should be doubled (that is, inside the R string literal it should be quadrupled as you need a \ to escape \ for the R engine to "see" a backslash).
Actually, if you want to match a newline, you just need to use \n in the regex pattern, you may either use "\n" or "\\n" as both TRE and PCRE regex engines parse LF and a \n regex escape as a newline char matching pattern. These four are equivalent:
gsub("\n([^\n])(\\s{1})?", "\\1", S1)
gsub("\\n([^\n])(\\s{1})?", "\\1", S1)
gsub("\n([^\\\\n])(\\s{1})?", "\\1", S1, perl=TRUE)
gsub("\\n([^\\\\n])(\\s{1})?", "\\1", S1, perl=TRUE)
If the \n must be optional, just add ? quantifier after it, no need wrapping it with a group:
gsub("\n?([^\n])(\\s{1})?", "\\1", S1)
^
And simplifying it further:
gsub("\n?([^\n])\\s?", "\\1", S1)
And also, if by [^\n] you want to match any char but a newline, just use . with (?n) inline modifier:
gsub("(?n)(.)(\\s{1})?", "\\1", S1)
See R demo online.
A couple of issues. The is not a backslash in your S object (it's an escape-operator rather than a character) and there is a predefined digit character class that can be negated:
gsub("[^[:digit:]]", "", S)
[1] "345"
If in the other hand you wanted to exclude the newline character and the spaces, it would be done by removing one of the escape operators, since they are not needed except for the small group of special characters that exist in the character class context:
gsub("[\n ]", "", S)
[1] "345"
Related
In a R script (that I would read with readLines), I want to replace every occurence of qux$foo$bar with qux[["foo"]][["bar]]. But I'm not a regex master.
I started with this regex:
> gsub("(\\w*)(\\$)(\\w*)", '\\1[["\\3"]]', "qux$foo$bar; input$test$a$a") %>% cat
qux[["foo"]][["bar"]]; input[["test"]][["a"]][["a"]]
Nice. But I also want to handle the case of backticks. So I tried:
> gsub("(\\w*)(\\$)`{0,1}(\\w*)`{0,1}", '\\1[["\\3"]]', "qux$`foo`; bar$`baz`; x$uvw") %>% cat
qux[["foo"]]; bar[["baz"]]; x[["uvw"]]
Looks correct. But between the backticks, there could be a space, and the previous way does not work in this case. So I tried the following, which neither does not work:
gsub("(\\w*)(\\$)`{0,1}(.*)`{0,1}", '\\1[["\\3"]]', "qux$`fo o`") %>% cat
qux[["fo o`"]]
Could you help to find the right regex pattern? It seems that instead of \\w I need something which means match a "word that can contain spaces".
You can use
gsub('(\\w*)(?|\\$`([^`]*)`|\\$([^\\s$]+))', '\\1[["\\2"]]', x, perl=TRUE)
## Or
gsub('\\$`([^`]*)`|\\$([^\\s$]+)', '[["\\1\\2"]]', x, perl=TRUE)
See the regex #1 demo and regex #2 demo. Details:
(\w*) - Group 1 (\1): zero or more word chars
(?|$`([^`]*)`|$([^\s$]+)) - a branch reset group matching either
$`([^`]*)` - $, backtick, Group 2 (\2) capturing zero or more non-backtick chars, and a backtick.
| - or
$([^\s$]+) - $, then Group 2 (\2) capturing one or more chars other than whitespace and $
See the R demo:
x <- c('qux$foo$bar','qux$foo$bar; input$test$a$a','qux$`foo`; bar$`baz`; x$uvw','qux$`fo o`', 'q_ux$f_o_o$b.a_r')
gsub('(\\w*)(?|\\$`([^`]*)`|\\$([^\\s$]+))', '\\1[["\\2"]]', x, perl=TRUE)
## Or
## gsub('\\$`([^`]*)`|\\$([^\\s$]+)', '[["\\1\\2"]]', x, perl=TRUE)
Output:
[1] "qux[[\"foo\"]][[\"bar\"]]"
[2] "qux[[\"foo\"]][[\"bar;\"]] input[[\"test\"]][[\"a\"]][[\"a\"]]"
[3] "qux[[\"foo\"]]; bar[[\"baz\"]]; x[[\"uvw\"]]"
[4] "qux[[\"fo o\"]]"
[5] "q_ux[[\"f_o_o\"]][[\"b.a_r\"]]"
Note: backslashes in the output are console artifacts to keep the double quoted strings valid string literals, they are not part of the plain text output.
You might repeat optional spaces before and after matching 1 or more word characters.
You don't need a capture group for the $ but instead you could use a capture group to pair up the backtick in case it is there or not using a backreference to group 2.
To repeat 0+ whitespace chars you can also use \s but that could also match a newline.
Note that \w* matches optional word chars, and {0,1} can be written as ?
(\w*)\$(`?)( *\w+(?: +\w+)* *)\2
The pattern matches:
(\w*) Capture group 1 Match optional word characters
\$ Match $
(`?) Capture group 2, optionally match a backtick
( *\w+(?: +\w+)* *) Capture group 3 Match repetitions of word characters between spaces
\2 Backreference to what is captured in group 2 (yes or no backtick)
Regex demo
gsub("(\\w*)\\$(`?)( *\\w+(?: +\\w+)* *)\\2", '\\1[["\\3"]]', "qux$fo o$bar", perl=TRUE)
Output
[1] "qux[[\"fo o\"]][[\"bar\"]]"
I have the string in R
BLCU142-09|Apodemia_mejicanus
and I would like to get the result
Apodemia_mejicanus
Using the stringr R package, I have tried
str_replace_all("BLCU142-09|Apodemia_mejicanus", "[[A-Z0-9|-]]", "")
# [1] "podemia_mejicanus"
which is almost what I need, except that the A is missing.
You can use
sub(".*\\|", "", x)
This will remove all text up to and including the last pipe char. See the regex demo. Details:
.* - any zero or more chars as many as possible
\| - a | char (| is a special regex metacharacter that is an alternation operator, so it must be escaped, and since string literals in R can contain string escape sequences, the | is escaped with a double backslash).
See the R demo online:
x <- c("BLCU142-09|Apodemia_mejicanus", "a|b|c|BLCU142-09|Apodemia_mejicanus")
sub(".*\\|", "", x)
## => [1] "Apodemia_mejicanus" "Apodemia_mejicanus"
We can match one or more characters that are not a | ([^|]+) from the start (^) of the string followed by | in str_remove to remove that substring
library(stringr)
str_remove(str1, "^[^|]+\\|")
#[1] "Apodemia_mejicanus"
If we use [A-Z] also to match it will match the upper case letter and replace with blank ("") as in the OP's str_replace_all
data
str1 <- "BLCU142-09|Apodemia_mejicanus"
You can always choose to _extract rather than _remove:
s <- "BLCU142-09|Apodemia_mejicanus"
stringr::str_extract(s,"[[:alpha:]_]+$")
## [1] "Apodemia_mejicanus"
Depending on how permissive you want to be, you could also use [[:alpha:]]+_[[:alpha:]]+ as your target.
I would keep it simple:
substring(my_string, regexpr("|", my_string, fixed = TRUE) + 1L)
I have defined
vec <- "5f 110y, Fast"
and
gsub("[\\s0-9a-z]+,", "", vec)
gives "5f Fast"
I would have expected it to give "Fast" since everything before the comma should get matched by the regex.
Can anyone explain to me why this is not the case?
You should keep in mind that, in TRE regex patterns, you cannot use regex escapes like \s, \d, \w inside bracket expressions.
So, the regex in your case, "[\\s0-9a-z]+,", matches 1 or more \, s, digits and lowercase ASCII letters, and then a single ,.
You may use POSIX character classes instead, like [:space:] (any whitespaces) or [:blank:] (horizontal whitespaces):
> gsub("[[:space:]0-9a-z]+,", "", vec)
[1] " Fast"
Or, use a PCRE regex with \s and perl=TRUE argument:
> gsub("[\\s0-9a-z]+,", "", vec, perl=TRUE)
[1] " Fast"
To make \s match all Unicode whitespaces, add (*UCP) PCRE verb at the pattern start: gsub("(*UCP)[\\s0-9a-z]+,", "", vec, perl=TRUE).
Could you please try folllowing and let me know if this helps you.
vec <- c("5f 110y, Fast")
gsub(".*,","",vec)
OR
gsub("[[:alnum:]]+ [[:alnum:]]+,","",vec)
A tidyverse solution would be to use str_replace with you original regex:
library(stringr)
str_replace(vec, "[\\s0-9a-z]+,", "")
Try a different regex:
gsub("[[:blank:][:digit:][:lower:]]+,", "", vec)
#[1] " Fast"
Or, to remove the space after the comma,
gsub("[[:blank:][:digit:][:lower:]]+, ", "", vec)
#[1] "Fast"
I tried to search for the solution, but it appears that there is no clear one for R.
I try to split the string by the pattern of, let's say, space and capital letter and I use stringr package for that.
x <- "Foobar foobar, Foobar foobar"
str_split(x, " [:upper:]")
Normally I would get:
[[1]]
[1] "Foobar foobar," "oobar foobar"
The output I would like to get, however, should include the letter from the delimiter:
[[1]]
[1] "Foobar foobar," "Foobar foobar"
Probably there is no out of box solution in stringr like back-referencing, so I would be happy to get any help.
You may split with 1+ whitespaces that are followed with an uppercase letter:
> str_split(x, "\\s+(?=[[:upper:]])")
[[1]]
[1] "Foobar foobar," "Foobar foobar"
Here,
\\s+ - 1 or more whitespaces
(?=[[:upper:]]) - a positive lookahead (a non-consuming pattern) that only checks for an uppercase letter immediately to the right of the current location in string without adding it to the match value, thus, preserving it in the output.
Note that \s matches various whitespace chars, not just plain regular spaces. Also, it is safer to use [[:upper:]] rather than [:upper:] - if you plan to use the patterns with other regex engines (like PCRE, for example).
We could use a regex lookaround to split at the space between a , and upper case character
str_split(x, "(?<=,) (?=[A-Z])")[[1]]
#[1] "Foobar foobar," "Foobar foobar"
Here are some examples from my data:
a <-c("sp|Q9Y6W5|","sp|Q9HB90|,sp|Q9NQL2|","orf|NCBIAAYI_c_1_1023|",
"orf|NCBIACEN_c_10_906|,orf|NCBIACEO_c_5_1142|",
"orf|NCBIAAYI_c_258|,orf|aot172_c_6_302|,orf|aot180_c_2_405|")
For a: The individual strings can contain even more entries of "sp|" and "orf"
The results have to be like this:
[1] "sp|Q9Y6W5" "sp|Q9HB90,sp|Q9NQL2" "orf|NCBIAAYI_c_1_1023"
"orf|NCBIACEN_c_10_906,orf|NCBIACEO_c_5_1142"
"orf|NCBIAAYI_c_258,orf|aot172_c_6_302,orf|aot180_c_2_405"
So the aim is to remove the last "|" for each "sp|" and "orf|" entry. It seems that "|" is a special challenge because it is a metacharacter in regular expressions. Furthermore, the length and composition of the "orf|" entries varying a lot. The only things they have in common is "orf|" or "sp|" at the beginning and that "|" is on the last position. I tried different things with gsub() but also with the stringr package or regexpr() or [:punct:], but nothing really worked. Maybe it was just the wrong combination.
We can use gsub to match the | that is followed by a , or is at the end ($) of the string and replace with blank ("")
gsub("[|](?=(,|$))", "", a, perl = TRUE)
#[1] "sp|Q9Y6W5"
#[2] "sp|Q9HB90,sp|Q9NQL2"
#[3] "orf|NCBIAAYI_c_1_1023"
#[4] "orf|NCBIACEN_c_10_906,orf|NCBIACEO_c_5_1142"
#[5] "orf|NCBIAAYI_c_258,orf|aot172_c_6_302,orf|aot180_c_2_405"
Or we split by ,', remove the last character withsubstr, andpastethelist` elements together
sapply(strsplit(a, ","), function(x) paste(substr(x, 1, nchar(x)-1), collapse=","))
An easy alternative that might work. You need to escape the "|" using "\\|".
# Input
a <-c("sp|Q9Y6W5|","sp|Q9HB90|,sp|Q9NQL2|","orf|NCBIAAYI_c_1_1023|",
"orf|NCBIACEN_c_10_906|,orf|NCBIACEO_c_5_1142|",
"orf|NCBIAAYI_c_258|,orf|aot172_c_6_302|,orf|aot180_c_2_405|")
# Expected output
b <- c("sp|Q9Y6W5", "sp|Q9HB90,sp|Q9NQL2", "orf|NCBIAAYI_c_1_1023" ,
"orf|NCBIACEN_c_10_906,orf|NCBIACEO_c_5_1142" ,
"orf|NCBIAAYI_c_258,orf|aot172_c_6_302,orf|aot180_c_2_405")
res <- gsub("\\|,", ",", gsub("\\|$", "", a))
all(res == b)
#[1] TRUE
You could construct a single regex call to gsub, but this is simple and easy to understand. The inner gsub looks for | and the end of the string and removes it. The outer gsub looks for ,| and replaces with ,.
You do not have to use a PCRE regex here as all you need can be done with the default TRE regex (if you specify perl=TRUE, the pattern is compiled with a PCRE regex engine and is sometimes slower than TRE default regex engine).
Here is the single simple gsub call:
gsub("\\|(,|$)", "\\1", a)
See the online R demo. No lookarounds are really necessary, as you see.
Pattern details
\\| - a literal | symbol (because if you do not escape it or put into a bracket expression it will denote an alternation operator, see the line below)
(,|$) - a capturing group (referenced to with \1 from the replacement pattern) matching either of the two alternatives:
, - a comma
| - or (the alternation operator)
$ - end of string anchor.
The \1 in the replacement string tells the regex engine to insert the contents stored in the capturing group #1 back into the resulting string (so, the commas are restored that way where necessary).