Reputation: 10493
Let's say using Javascript, I want to match a string that ends with [abcde]*
but not with abc
.
So the regex should match xxxa
, xxxbc
, xxxabd
but not xxxabc
.
I am utterly confused.
Edit: I have to use regex for some reason, i cannot do something if (str.endsWith("abc"))
Upvotes: 17
Views: 57017
Reputation: 37806
Just want to say to @maček that you answer is simple and clear with !
in the beginning
But I really wanted the not operator to be inside the regexp so i could use it with eg: Array::some
, Array::filter
, Array::find
, Array::findIndex
and without having to create a function or a wile loop
Here is an example:
var items = ["ja", "ka", "mf", "bg", "vb", "b"]
var regex = /^((?!a$|b$).)*$/; // match a string that doesn't end with a or b
var matched = items.filter(RegExp.prototype.test, regex);
alert(matched); // result: ["mf", "bg"]
Upvotes: 1
Reputation: 383746
The solution is simple: use negative lookahead:
(?!.*abc$)
This asserts that the string doesn't end with abc
.
You mentioned that you also need the string to end with [abcde]*
, but the *
means that it's optional, so xxx
matches. I assume you really want [abcde]+
, which also simply means that it needs to end with [abcde]
. In that case, the assertions are:
(?=.*[abcde]$)(?!.*abc$)
See regular-expressions.info for tutorials on positive and negative lookarounds.
I was reluctant to give the actual Javascript regex since I'm not familiar with the language (though I was confident that the assertions, if supported, would work -- according to regular-expressions.info, Javascript supports positive and negative lookahead). Thanks to Pointy and Alan Moore's comments, I think the proper Javascript regex is this:
var regex = /^(?!.*abc$).*[abcde]$/;
Note that this version (with credit to Alan Moore) no longer needs the positive lookahead. It simply matches .*[abcde]$
, but first asserting ^(?!.*abc$)
.
Upvotes: 31
Reputation: 77778
Either the question is not properly defined, or everyone is overlooking a simple answer.
var re = /abc$/;
!re.test("xxxa"); // pass
!re.test("xxxbc"); // pass
!re.test("xxxabd"); // pass
!re.test("xxxabc"); // fail
All of these end in /[abcde]*
/
Upvotes: 16
Reputation: 15634
Firstly, note every string ends with [abcde]*
, as that allows zero width. Thus we're really just looking for a regex that matches strings that don't end in abc
. Easy.
([^c]|[^b]c|[^a]bc)$
That's something that's not c
, something that's not b
followed by c
, or something that's not a
followed by bc
, and whichever option of those, then followed by the end of the string.
Upvotes: 2
Reputation: 413720
Hmm ...
var regex = /(ab[abde]|[abcde])$/; // wrong
maybe? wait no; hold on:
var regex = /(ab[abde]|([^a].|.[^b])[abcde]|\b.?[abcde])$/;
So that's "ab" followed by "a", "b", "d", or "e"; or any two-character sequence where the first character isn't "a" or the second character isn't "b", followed by "a" through "e"; or any word boundary followed by any character (possibly) followed by "a" through "e". The last clause is to deal with short strings; it's sort-of cheating but in this case it works.
Upvotes: 0