I got RE of strings that starts with some string X and contains some string Y which was
const startsWith = 't'
const contains = 'te'
const re = new RegExp(`(?=.*${contains})^${startsWith}`)
re.test('teacher') // Result = true
But when I try to change it to ends with X and contains Y like
const endsWith = 'e'
const contains = 'te'
const re = new RegExp(`(?=.*${contains})${endsWith}\$`)
re.test('ate') // Result = false
I did not get the desired result
I need a regex which would give true when word like 'ate' contains 'te' and also ends with 'e', also gives true when word like 'steve' contains 'te' and ends with 'e'. Currently my endsWith regex giving false on both.
CodePudding user response:
The "endsWith" part is always at the end of the string.
The generated regex looks like this (?=.*te)e$
and when the lookahead succeeds asserting (non consuming) te
, the position is still at the start of the string.
The next part of the pattern tries to match e
at the end of the string, but the position did not move yet and it did not match at
before it to get to the e
at the end.
You might write the pattern using .*
in between to get to the end of the string, and add an anchor ^
before the lookahead to perform the assertion only once.
Note that you can escape the \$
but you don't have to.
const endsWith = 'e'
const contains = 'te'
const re = new RegExp(`^(?=.*${contains}).*${endsWith}$`)
console.log(re.test('ate'))
CodePudding user response:
1st let's understand why the 1st one is working and why the 2nd one is not working.
Example First:
const startsWith = 't'
const contains = 'te'
const re = new RegExp(`(?=.*${contains})^${startsWith}`)
re.test('teacher') // Result = true
Debug:
(?=.*te)^t
Explain:
Here (?=.*te) is "Positive lookahead", which means regex will start matching this and then will look ahead for the next conditions/rules.
(
?= Matches a group after the main expression (^t) without including it in the result.
. DOT, Matches any character except linebreaks
* Matches 0 or more of the preceding token
t Check for character 't'
e Check for character 'e'
)
^ Matches the beginning of the string. This matches a position, not a character.
t Check for character 't'
Human Explain:
Find every string which contains 'te' and ready to look after next rule which is find string which starts with 't'
Hence:
teacher //true, because it has 'te' and starts with 't'
thirdteacher //true, because it has 'te' and starts with 't'
twoteacher //true, because it has 'te' and starts with 't'
myteacher //false, because it has 'te' but does not start with 't'
Example Second:
const endsWith = 'e'
const contains = 'te'
const re = new RegExp(`(?=.*${contains})${endsWith}\$`)
re.test('ate') // Result = false
Debug:
(?=.*te)e$
Explain:
Here (?=.*te) is "Positive lookahead", which means regex will start matching things after the main expression.
(
?= Matches a group after the main expression (e$) without including it in the result.
. DOT, Matches any character except linebreaks
* Matches 0 or more of the preceding token
t Check for character 't'
e Check for character 'e'
)
e Check for character 'e'
$ Matches the end of the string. This matches a position, not a character.
Human Explain:
Find every string which contains 'te' but as the main expression first find a string which ends as the last character 'e'. it's end man! whoa!! yeah!! end .. end.. nothing after to match... it's ending.
- Since... "Positive lookahead" failed here due to the main expression ends the search here using '$'
Hence "Positive lookahead" can not proceed for "lookahead"
Hence:
regex will find ... nothing, no match Ssshhhh... silence
So what is the solution?
You have 2 options either use @The fourth bird solution which is '(?=.*te).*e$' in debug mode.
Here '.' is the main expression and gives "Positive lookahead" a chance to move and find strings and matches after ..
(
?= Matches a group after the main expression (e$) without including it in the result.
. DOT, Matches any character except linebreaks
* Matches 0 or more of the preceding token
t Check for character 't'
e Check for character 'e'
)
. DOT, Matches any character except linebreaks
* Matches 0 or more of the preceding token
e Check for character 'e'
$ Matches the end of the string. This matches a position, not a character.
Human Explain:
Hey! regex please bring me a string which contains 'te' and ends with 'e'
Execution Pipeline for 'soulmate':
(?=.*te) -- did you found 'te' yes 'solema*te*'
.* -- main expression is find everything, did you found, yes 'soulmate'
e$ -- last expression is 'ends with e', did you find, yes 'soulmat*e*'
Master, here is the result - 'soulmate'
// false tomato page
// false yellow-teeth
// true teeth-color-is-white
// true ate
// false future terminator
// false AI is awful and should never be replaced with the human race.
// true AI is good for telephones but awful for the human race
// true I am running late
// true e-gate
// true soulmate
// false time
// false race
// false ate-milan-cafes
// true tell me the truth if mighty god is everywhere
Another option is using the native Javascript function. startsWith, includes and endsWith.
Example:
<script>
var first = "teacher";
var startwith = first.startsWith("t");
var contains = first.includes("te");
alert((contains && startwith)); // true
var second = "ate";
var contains = first.includes("te");
var endwith = second.endsWith("e");
alert((contains && endwith)); // true
</script>
-- Thank you