Negating Alternation In Regular Expressions - regex

I can use "Alternation" in a regular expression to match any occurance of "cat" or "dog" thusly:
(cat|dog)
Is it possible to NEGATE this alternation, and match anything that is NOT "cat" or "dog"?
If so, how?
For Example:
Let's say I'm trying to match END OF SENTENCE in English, in an approximate way.
To Wit:
(\.)(\s+[A-Z][^.]|\s*?$)
With the following paragraph:
The quick brown fox jumps over the lazy dog. Once upon a time Dr. Sanches, Mr. Parsons and Gov. Mason went to the store. Hello World.
I incorrectly find "end of sentence" at Dr., Mr., and Gov.
(I'm testing using http://regexpal.com/ in case you want to see what I'm seeing with the above example)
Since this is incorrect, I would like to say something like:
!(Dr\.|Mr\.|Gov\.)(\.)(\s+[A-Z][^.]|\s*?$)
Of course, this isn't working, which is why I seek help.
I also tried !/(Dr.|Mr.|Gov.)/, and !~ which were no help whatsoever.
How can I avoid matches for "Dr.", "Mr." and "Gov.", etc?
Thanks in advance.

It is not possible. You would normally do this using negative lookbehind (?<!…), but JavaScript's regex flavor does not support this. Instead, you will have to filter the matches after the fact to discard those you don't want.

In language like Perl/awk, there's the !~ operator
$string !~ /(cat|dog)/
In Actionscript, you can just use NOT operator ! to negate a match. See here for reference. Also here for regex flavors comparison

You can do this:
!/(cat|dog)/
EDIT: You should've included the programming language on your question. Its Actionscript right? I'm not an actionscript coder but AFAIK its done like this:
var pattern2:RegExp = !/(cat|dog)/;

(?!NotThisStuff) is what you want, otherwise known as a negative lookahead group.
Unfortunately, it will not work as you intend. /(?!Dr\.)(\.)/ will still return the periods that belong to "Dr. Sanches" because of the second grouping. The Regex parser will say to itself, "Yep, this '.' isn't 'Dr.'" /((?!Dr).)/ won't work either, though I believe it should.
And what's more, you'll end up looking through all the sentence "ends" anyway. Actionscript doesn't have a "match all," only a match first. You have to set the global flag (or add g to the end of your regex) and call exec until your result object is null.
var string = 'The quick brown fox jumps over the lazy dog. Once upon a time Dr. Sanches, Mr. Parsons and Gov. Mason went to the store. Hello World.';
var regx:RegExp = /(?!Dr\.)(\.)/g;
var result:Object = regx.exec(string);
for (var i = 0; i < 10; i++) { // paranoia
if (result == null || result.index == 0) break; // again: paranoia
trace(result.index, result);
result = regx.exec(string);
}
// trace results:
//43 .,.
//64 .,.
//77 .,.
//94 .,.
//119 .,.
//132 .,.

Related

Scala. Regexp can't remove symbol ^

I need split sentence to words removing redundant characters.
I prepared regexp for that:
val wordCharacters = """[^A-z'\d]""".r
right now I have rule which can be used to handle task in next way:
wordCharacters.split(words)
.filterNot(_.isEmpty)
where words any sentence I need to parse.
But issue is that in case I try to handle "car: carpet, as,,, java: javascript!!&#$%^&" I get one more word ^. Trying to change my regex and without ^ I'm getting much more issues for different cases...
Is any ideas how to solve it?
P.S.
If somebody want to play with it try link or code below please:
val wordCharacters = """[^A-z'\d]""".r
val stringToInt =
wordCharacters.split("car: carpet, as,,, java: javascript!!&#$%^&")
.filterNot(_.isEmpty)
.toList
println(stringToInt)
Expected result is:
List(car, carpet, as, java, javascript)
The part A-z is not exactly what you want. Probably you assume that lower a comes immediately after upper Z, but there are some other characters in between, and one of them is ^.
So, correcting the regex as
"""[^A-Za-z'\d]""".r
would fix the issue.
Have a look at the order of characters:
https://en.wikipedia.org/wiki/List_of_Unicode_characters
I'd be tempted to start with \W and expand from there.
"\\W+".r.split("car: carpet, as,,, java: javascript!!&#$%^&")
//res0: Array[String] = Array(car, carpet, as, java, javascript)

How to access the results of .match as string value in Crystal lang

In many other programming languages, there is a function which takes as a parameter a regular expression and returns an array of string values. This is true of Javascript and Ruby. The .match in crystal, however, does 1) not seem to accept the global flag and 2) it does not return an array but rather a struct of type Regex::MatchData. (https://crystal-lang.org/api/0.25.1/Regex/MatchData.html)
As an example the following code:
str = "Happy days"
re = /[a-z]+/i
matches = str.match(re)
puts matches
returns Regex::MatchData("Happy")
I am unsure how to convert this result into a string or why this is not the default as it is in the inspiration language (Ruby). I understand this question probably results from my inexperience dealing with structs and compiled languages but I would appreciate an answer in hopes that it might also help someone else coming from a JS/Ruby background.
What if I want to convert to a string merely the first match?
puts "Happy days"[/[a-z]+/i]?
puts "Happy days".match(/[a-z]+/i).try &.[0]
It will try to match a string against /[a-z]+/i regex and if there is a match, Group 0, i.e. the whole match, will be output. Note that the ? after [...] will make it fail gracefully if there is no match found. If you just use puts "??!!"[/[a-z]+/i], an exception will be thrown.
See this online demo.
If you want the functionality similar to String#scan that returns all matches found in the input, you may use (shortened version only left as per #Amadan's remark):
matches = str.scan(re).map(&.string)
Output of the code above:
["Happy days", "Happy days"]
Note that:
String::scan will return an array of Regex::MatchData for each match.
You can call .string on the match to return the actual matched text.
Actually the posted example returns a #<MatchData "Happy"> in Ruby, which also has no "global" flag – thats what String#scan(Regex) is for as mentioned by others.
If you want only a single match without going through Regex::MatchData, you can use String#[](Regex):
str = "Happy days"
p str[/[a-z]+/i] # => "Happy"

error: multiple repeat for regex in robot [duplicate]

I'm trying to determine whether a term appears in a string.
Before and after the term must appear a space, and a standard suffix is also allowed.
Example:
term: google
string: "I love google!!! "
result: found
term: dog
string: "I love dogs "
result: found
I'm trying the following code:
regexPart1 = "\s"
regexPart2 = "(?:s|'s|!+|,|.|;|:|\(|\)|\"|\?+)?\s"
p = re.compile(regexPart1 + term + regexPart2 , re.IGNORECASE)
and get the error:
raise error("multiple repeat")
sre_constants.error: multiple repeat
Update
Real code that fails:
term = 'lg incite" OR author:"http++www.dealitem.com" OR "for sale'
regexPart1 = r"\s"
regexPart2 = r"(?:s|'s|!+|,|.|;|:|\(|\)|\"|\?+)?\s"
p = re.compile(regexPart1 + term + regexPart2 , re.IGNORECASE)
On the other hand, the following term passes smoothly (+ instead of ++)
term = 'lg incite" OR author:"http+www.dealitem.com" OR "for sale'
The problem is that, in a non-raw string, \" is ".
You get lucky with all of your other unescaped backslashes—\s is the same as \\s, not s; \( is the same as \\(, not (, and so on. But you should never rely on getting lucky, or assuming that you know the whole list of Python escape sequences by heart.
Either print out your string and escape the backslashes that get lost (bad), escape all of your backslashes (OK), or just use raw strings in the first place (best).
That being said, your regexp as posted won't match some expressions that it should, but it will never raise that "multiple repeat" error. Clearly, your actual code is different from the code you've shown us, and it's impossible to debug code we can't see.
Now that you've shown a real reproducible test case, that's a separate problem.
You're searching for terms that may have special regexp characters in them, like this:
term = 'lg incite" OR author:"http++www.dealitem.com" OR "for sale'
That p++ in the middle of a regexp means "1 or more of 1 or more of the letter p" (in the others, the same as "1 or more of the letter p") in some regexp languages, "always fail" in others, and "raise an exception" in others. Python's re falls into the last group. In fact, you can test this in isolation:
>>> re.compile('p++')
error: multiple repeat
If you want to put random strings into a regexp, you need to call re.escape on them.
One more problem (thanks to Ωmega):
. in a regexp means "any character". So, ,|.|;|:" (I've just extracted a short fragment of your longer alternation chain) means "a comma, or any character, or a semicolon, or a colon"… which is the same as "any character". You probably wanted to escape the ..
Putting all three fixes together:
term = 'lg incite" OR author:"http++www.dealitem.com" OR "for sale'
regexPart1 = r"\s"
regexPart2 = r"(?:s|'s|!+|,|\.|;|:|\(|\)|\"|\?+)?\s"
p = re.compile(regexPart1 + re.escape(term) + regexPart2 , re.IGNORECASE)
As Ωmega also pointed out in a comment, you don't need to use a chain of alternations if they're all one character long; a character class will do just as well, more concisely and more readably.
And I'm sure there are other ways this could be improved.
The other answer is great, but I would like to point out that using regular expressions to find strings in other strings is not the best way to go about it. In python simply write:
if term in string:
#do whatever
i have an example_str = "i love you c++" when using regex get error multiple repeat Error. The error I'm getting here is because the string contains "++" which is equivalent to the special characters used in the regex. my fix was to use re.escape(example_str ), here is my code.
example_str = "i love you c++"
regex_word = re.search(rf'\b{re.escape(word_filter)}\b', word_en)
Also make sure that your arguments are in the correct order!
I was trying to run a regular expression on some html code. I kept getting the multiple repeat error, even with very simple patterns of just a few letters.
Turns out I had the pattern and the html mixed up. I tried re.findall(html, pattern) instead of re.findall(pattern, html).
A general solution to "multiple repeat" is using re.escape to match the literal pattern.
Example:
>>>> re.compile(re.escape("c++"))
re.compile('c\\+\\+')
However if you want to match a literal word with space before and after try out this example:
>>>> re.findall(rf"\s{re.escape('c++')}\s", "i love c++ you c++")
[' c++ ']

How to negate regex validation string?

I want to replace all the string except the #[anyword]
I have string like this:
yng nnti dkasih tau :)"#mazayalinda: Yg klo ada cenel busana muslim aku mau ikutan dong "#noviwahyu10: Model ! Pasti gk blh klo k
and the #mazayalinda and #noviwahyu10 matches my regex #\w*.
However, I need to get rid all of the string, except for those 2 words above. We need to do the negation, but I am confuses about combining 2 regex, which are the regex to match the #[anyword] and the one to get rid all of the sentence except those 2 words.
Any ideas?
It's not completely clear from the context if this is a viable solution, but when you want to replace everything except a certain pattern it sounds more like you want a regex search rather than a replacement. For example, in python it might look like:
>>> import re
>>> s = 'yng nnti dkasih tau :)"#mazayalinda: Yg klo ada cenel busana muslim aku mau ikutan dong "#noviwahyu10: Model ! Pasti gk blh klo k'
>>> re.findall(r'#\w+', s)
['#mazayalinda', '#noviwahyu10']
Edit: in js, something like this would be more appropriate:
var s = 'yng nnti dkasih tau :)"#mazayalinda: Yg klo ada cenel busana muslim aku mau ikutan dong "#noviwahyu10: Model ! Pasti gk blh klo k';
// code from http://www.activestate.com/blog/2008/04/javascript-refindall-workalike
var rx = new RegExp("#\\w+", "g");
var matches = new Array();
while((match = rx.exec(s)) !== null){
matches.push(match);
}
After this, matches contains all the matched strings. You can always join it back together if needed into a single string.
It seems to me that you want to use capturing groups, not exactly negate the rest of the string, a regex like:
[^#]*(#\w+)[^#]*
Will capture those entries in capturing groups, and then, depending on your language, you can access each of the captured strings: http://rubular.com/r/qHKb35OK3g
use this regex (?<=^|#\w+\b)[^#]+ and union matches
Well, I'm not entirely sure I understand the question, but if you want to keep just the names and use the rest just "to get rid of it", why don't you simply save the names and ignore the rest ?
If you're keen on matching the "non-name pattern" - this seems to be an excerpt from some kind of conversation, where every message starts with ':'. If so, then using this should simply do the trick.
:[^#]*
You can use zero-width negative assertion, i.e., #(?!mazayalinda|noviwahyu10)\w.
This requires some sophisticated regular expression engine like Perl, Ruby, Java and so on.
If you have classic engine, the way as #pcalcao sais is best.

Regexp: Keyword followed by value to extract

I had this question a couple of times before, and I still couldn't find a good answer..
In my current problem, I have a console program output (string) that looks like this:
Number of assemblies processed = 1200
Number of assemblies uninstalled = 1197
Number of failures = 3
Now I want to extract those numbers and to check if there were failures. (That's a gacutil.exe output, btw.) In other words, I want to match any number [0-9]+ in the string that is preceded by 'failures = '.
How would I do that? I want to get the number only. Of course I can match the whole thing like /failures = [0-9]+/ .. and then trim the first characters with length("failures = ") or something like that. The point is, I don't want to do that, it's a lame workaround.
Because it's odd; if my pattern-to-match-but-not-into-output ("failures = ") comes after the thing i want to extract ([0-9]+), there is a way to do it:
pattern(?=expression)
To show the absurdity of this, if the whole file was processed backwards, I could use:
[0-9]+(?= = seruliaf)
... so, is there no forward-way? :T
pattern(?=expression) is a regex positive lookahead and what you are looking for is a regex positive lookbehind that goes like this (?<=expression)pattern but this feature is not supported by all flavors of regex. It depends which language you are using.
more infos at regular-expressions.info for comparison of Lookaround feature scroll down 2/3 on this page.
If your console output does actually look like that throughout, try splitting the string on "=" when the word "failure" is found, then get the last element (or the 2nd element). You did not say what your language is, but any decent language with string splitting capability would do the job. For example
gacutil.exe.... | ruby -F"=" -ane "print $F[-1] if /failure/"