How do I use regex to match alphabetical characters only? - r

I want to gsub a string that contains only characters and white spaces, for example the string "to delete". I have tried this:
gsub('[^[:alpha:]$]',NA, "to delete", ignore.case=T)
But I get an NA also when the string contains digits, for example:
gsub('[^[:alpha:]$]',NA, "to 1 delete", ignore.case=T)
Anybody could tell me what I am doing wrong? Thanks.

Your regex only tests for a single unanchored bracket expression. This means that any string that has any character which matches the bracket expression will match the regex.
Your bracket expression tests for "not alphabetic not dollar". This matches many things, including spaces, digits, and all punctuation characters other than dollar.
It sounds like you want to match only strings which consist in their entirety of only alphabetic and whitespace characters. To achieve that you need an anchored multiplied bracket expression.
Also, you don't need gsub() for this; you only need sub(), since a regex that can only match the entirety of the input string cannot match multiple times within the input string.
Also, you don't need ignore.case=T, since the [:alpha:] character class already matches all alphabetics, regardless of letter-case.
regex <- '^[[:alpha:][:space:]]*$';
sub(regex,NA,'to delete');
## [1] NA
sub(regex,NA,'to 1 delete');
## [1] "to 1 delete"

Related

What is the regex pattern for extracting the substring to the left of four numbers attached to an uppercase word?

I have a string ARC GUNNA SPARKYA 2011QUARTER HORSE.
I'd like to extract only the ARC GUNNA SPARKYA part. I.e., everything to the left of the "2011QUARTER."
I will also have valid strings which I want the pattern NOT to match. Valid strings would be "10RUNS FAST" or "QUICKER 1".
Note that the above means I need a pattern which can explicitly pick up just any four numbers followed by the uppercase word "QUARTER."
I tried ([0-9A-Za-z]+( [0-9A-Za-z]+)+) but that pattern matches the part I want to keep too, so I can't use it to do something like gsub.
Can you please help me understand what regex pattern will accomplish this--particularly in R?
Thank you!
You could use sub with a capture group, and use that group in the replacement.
(.*?)\s+\d{4}QUARTER\b.*
Explanation
(.*?) Capture group 1, match any character, as few as possible
\s+ Match 1+ whitespace characters
\d{4}QUARTER\b Match 4 digits followed by the word QUARTER
.* Match the rest of the line
See a regex101 demo.
text <- "ARC GUNNA SPARKYA 2011QUARTER HORSE"
result = sub("(.*?)\\s+\\d{4}QUARTER\\b.*", "\\1", text)
result
Output
[1] "ARC GUNNA SPARKYA"

how to remove decimal point between numbers in R

I am trying to remove the decimal points in decimal numbers in R. Please note I want to keep the full stop of strings.
Example:
data= c("It's 6.00pm, and is late.")
I know that I have to use regex for this, but I am struggling. My desired output is:
"It's 6 00pm, and is late."
Thank you in advance.
Try this:
sub("(?<=\\d)\\.(?=\\d)", " ", data, perl = TRUE)
This solution uses lookbehind (?<=...) and lookahead (?=...)to assert that the period you wish to remove be enclosed by digits (thus avoiding matching the period at the sentence end). If you have several such cases within strings, then use gsubinstead of sub.
I suggest using a simple pattern to find the target text, then adding parenthesis to identify the parts of the matching text that you want to retain.
# Test data
data <- c("It's 6.00pm, and is late.")
The target pattern is a literal dot with a string of digits before and after it. \\d+ matches one or more digits and \\. matches a literal dot. Testing the pattern to see if it works:
grepl("\\d+\\.\\d+", data)
Result
TRUE
If we wanted too eliminate the whole thing we could do a simple replacement with an empty string. Testing if this targets the correct text:
sub("\\d+\\.\\d+", "", data)
Result
"It's pm, and is late."
Instead, to discard only a section of matched text we can identify the parts we want to keep, which is done by surrounding them with parenthesis. Once done we can refer to the captured text in the replacement. \\1 refers to the first chunk of text captured and \\2 refers to the second chunk of text, corresponding to the first and second sets of parenthesis
# pattern replacement
sub("(\\d+)\\.(\\d+)", "\\1\\2", data)
Result
[1] "It's 600pm, and is late."
This effectively removes the dot by omitting it from the replacement text.

R Character classes

Could anybody explain why "aba12" shows up, when I have specified {2}?
strings=c("Ab12","aba12","BA12","A 12b","B!","d", " ab")
grep("^[[:alpha:]]{2}", strings, value=TRUE)
You can use ...
grep("^[[:alpha:]]{2}[^[:alpha:]]", strings, value=TRUE)
# [1] "Ab12" "BA12"
[...] enumerates accepted characters and [^...] negates it. Further, from #Mako212:
^[[:alpha:]]{2} [...] tells the Regex engine to match the beginning of the string, then exactly two ASCII A-Z/a-z characters. It asserts nothing about the remainder of the string. Regex will process the remainder of the string, but there is no remaining criteria to match
My answer above expects a non-alpha character following the initial two. From MrFlick's comment:
If you also want to match "AB", then use
grep("^[[:alpha:]]{2}([^[:alpha:]]|$)", strings, value=TRUE)
to match a non-alpha character or end of string.

How to split a string by dashes outside of square brackets

I would like to split strings like the following:
x <- "abc-1230-xyz-[def-ghu-jkl---]-[adsasa7asda12]-s-[klas-bst-asdas foo]"
by dash (-) on the condition that those dashes must not be contained inside a pair of []. The expected result would be
c("abc", "1230", "xyz", "[def-ghu-jkl---]", "[adsasa7asda12]", "s",
"[klas-bst-asdas foo]")
Notes:
There is no nesting of square brackets inside each other.
The square brackets can contain any characters / numbers / symbols except square brackets.
The other parts of the string are also variable so that we can only assume that we split by - whenever it's not inside [].
There's a similar question for python (How to split a string by commas positioned outside of parenthesis?) but I haven't yet been able to accurately adjust that to my scenario.
You could use look ahead to verify that there is no ] following sooner than a [:
-(?![^[]*\])
So in R:
strsplit(x, "-(?![^[]*\\])", perl=TRUE)
Explanation:
-: match the hyphen
(?! ): negative look ahead: if that part is found after the previously matched hyphen, it invalidates the match of the hyphen.
[^[]: match any character that is not a [
*: match any number of the previous
\]: match a literal ]. If this matches, it means we found a ] before finding a [. As all this happens in a negative look ahead, a match here means the hyphen is not a match. Note that a ] is a special character in regular expressions, so it must be escaped with a backslash (although it does work without escape, as the engine knows there is no matching [ preceding it -- but I prefer to be clear about it being a literal). And as backslashes have a special meaning in string literals (they also denote an escape), that backslash itself must be escaped again in this string, so it appears as \\].
Instead of splitting, extract the parts:
library(stringr)
str_extract_all(x, "(\\[[^\\[]*\\]|[^-])+")
I am not familiar with r language, but I believe it can do regex based search and replace. Instead of struggling with one single regex split function, I would go in 3 steps:
replace - in all [....] parts by a invisible char, like \x99
split by -
for each element in the above split result(array/list), replace \x99 back to -
For the first step, you can find the parts by \[[^]]

keep only alphanumeric characters and space in a string using gsub

I have a string which has alphanumeric characters, special characters and non UTF-8 characters. I want to strip the special and non utf-8 characters.
Here's what I've tried:
gsub('[^0-9a-z\\s]','',"�+ Sample string here =�{�>E�BH�P<]�{�>")
However, This removes the special characters (punctuations + non utf8) but the output has no spaces.
gsub('/[^0-9a-z\\s]/i','',"�+ Sample string here =�{�>E�BH�P<]�{�>")
The result has spaces but there are still non utf8 characters present.
Any work around?
For the sample string above, output should be:
Sample string here
You could use the classes [:alnum:] and [:space:] for this:
sample_string <- "�+ Sample 2 string here =�{�>E�BH�P<]�{�>"
gsub("[^[:alnum:][:space:]]","",sample_string)
#> [1] "ï Sample 2 string here ïïEïBHïPïï"
Alternatively you can use PCRE codes to refer to specific character sets:
gsub("[^\\p{L}0-9\\s]","",sample_string, perl = TRUE)
#> [1] "ï Sample 2 string here ïïEïBHïPïï"
Both cases illustrate clearly that the characters still there, are considered letters. Also the EBHP inside are still letters, so the condition on which you're replacing is not correct. You don't want to keep all letters, you just want to keep A-Z, a-z and 0-9:
gsub("[^A-Za-z0-9 ]","",sample_string)
#> [1] " Sample 2 string here EBHP"
This still contains the EBHP. If you really just want to keep a section that contains only letters and numbers, you should use the reverse logic: select what you want and replace everything but that using backreferences:
gsub(".*?([A-Za-z0-9 ]+)\\s.*","\\1", sample_string)
#> [1] " Sample 2 string here "
Or, if you want to find a string, even not bound by spaces, use the word boundary \\b instead:
gsub(".*?(\\b[A-Za-z0-9 ]+\\b).*","\\1", sample_string)
#> [1] "Sample 2 string here"
What happens here:
.*? fits anything (.) at least 0 times (*) but ungreedy (?). This means that gsub will try to fit the smallest amount possible by this piece.
everything between () will be stored and can be refered to in the replacement by \\1
\\b indicates a word boundary
This is followed at least once (+) by any character that's A-Z, a-z, 0-9 or a space. You have to do it that way, because the special letters are contained in between the upper and lowercase in the code table. So using A-z will include all special letters (which are UTF-8 btw!)
after that sequence,fit anything at least zero times to remove the rest of the string.
the backreference \\1 in combination with .* in the regex, will make sure only the required part remains in the output.
stringr may use a differrent regex engine that supports POSIX character classes. The :ascii: names the class, which must generally be enclosed in square brackets [:asciii:], whithin the outer square bracket. The [^ indicates negation of the match.
library(stringr)
str_replace_all("�+ Sample string here =�{�>E�BH�P<]�{�>", "[^[:ascii:]]", "")
result in
[1] "+ Sample string here ={>EBHP<]{>"

Resources