I know how to find substrings using strpos, but I want to return True only if the letter t appears in a string, but not if that t is followed by "he". For example...
$str="The lion and dog are hungry"
The result would be Does not contain t because the only t in the string was part of the word "The".
$str="Their bedroom is ugly" should also return false because "Their" starts with T H E and there's not other t in the string.
$str="The cat and the dog are hungry" would result in Yes, this string contains a t because there's a t in CAT.
Add a comment
|
3 Answers
You need a negative lookbehind regex:
/t(?!h(?:e|is))/i
See the regex demo
Pattern details:
t- a literal chart(?!h(?:e|is))- a negative lookbehind that checks if its pattern matches the string after the current location and failing the match (returning false) if the match occurs:h- a literalh(?:e|is)- eithereoris(the(?:...|...)is a non-capturing group that does not keep submatches in the memory containing a|alternation operator)
/i- case insensitive modifier making the regex match in a case insensitive way.
Basically, this is a more efficient version of a t(?!he|his) regex (t not followed with he or his).
$re = '/t(?!h(?:e|is))/i';
if (preg_match($re,'The cat and the dog are hungry'))
echo 'true';
else
echo 'false';
4 Comments
Mostafa
/t(?!he)(?!his)/i becuase the asker update his question in the replies
Wiktor Stribiżew
@Mostafa: Good, I adjusted the pattern and the demo links are updated.
CheeseFlavored
Very good, detailed answer. I actually went with the less efficient
t(?!he|his) That works fine for me and it's easy to understand.Wiktor Stribiżew
With regexps, the best practice is to make sure they match linearly, the previous subpattern should not match at the same location as the next subpattern. Thus, it is not a good idea to use alternative branches starting with the same character(s). I agree in this concrete case that won't make much difference in performance, but if you think of expanding the pattern, or put it into a much longer pattern, you should bear this in mind.
Try this
<?php
$a = 'Their bedroom is ugly';
if (preg_match('/t(?!he)(?!his)/i',$a))
echo 'true';
else
echo 'false';
5 Comments
CheeseFlavored
Thanks for the quick answer. One more question... I'm not good with regex, How would I add another condition to it, for example, if I didn't want to include T H E or T H I So
The boy and this girl would result in false because the only T's are in The and This.Wiktor Stribiżew
/t[^the]/ matches a t that is followed with 1 char other than t, h, or e.Mostafa
@WiktorStribiżew I think it will not return true if the letter T in the end of the text, Can you try to update the answer
user1958756
You can add an 'i' after the last '/' to make the regex case insensitive. You could also replace 't' with a character class '[tT]' so it will match either 't' or 'T', you can also use an or '|' like this 't|T'
Wiktor Stribiżew
Using the
/i modifier is the preferred way, I think. Also, (?!he)(?!his) looks too verbose, the same effect is achieved with alternation inside the lookahead: (?!he|his), see my answer for details.You can use strpos to check to see if there's an 'he' after all the 't's you find:
<?php
$offest = 0;
$string = "the t the";
$result = 'No, this string does not contain t';
while ($pos1 = strpos($string,'t', $offset)) {
if ($pos2 = strpos($string,'the',$offset) {
if ($pos1 != $pos2) {
$result = 'Yes, this string contains t';
} else {
$offset = pos1;
}
} else {
$result = 'Yes, this string contains t';
}
}
echo $result;
but that's not the most efficient way to do it. IMHO the best thing to do would be to use a Regex
$string = "the t the";
$result = 'no';
if (preg_match('/[tT][^Hh]/')) {
$result = 'yes';
}
You can also use negative lookahead (a personal favorite technique):
$string = "the t the";
$result = 'no';
if (preg_match('/t(?!he)/i')) {
$result = 'yes';
}