I'm sorry if the question is unclear
I am trying to make a regular expression that replaces everything with ** at the beginning and end with "Test" (for now at least.)
Currently this is my pattern:
\*{2}[\w\s] \*{2}
This works so that strings like **Car**, **123**, **This is a test** get replaced with "Test", except also for example ***Bird*** becomes *Test*.
So my question is if there is a way to make sure strings only get replaced with "Test" when there's exactly two ** at beginning and end, no more (so ***Bird*** stays ***Bird*** and doesn't get replaced).
CodePudding user response:
In my opinion, you can have a lazy regex that does match the
*-chars-*pattern in a way where it doesn't bother about how many*are there before and after.Use
preg_replace_callbackto check with the captured groups and returnTestaccordingly if only 2*before and after meet this condition. This way, your code is much more readable and simple.
Snippet:
<?php
$newText = preg_replace_callback(
'/([*] )[^*] ([*] )/',
function ($matches) {
return strlen($matches[1]) == 2 && strlen($matches[2]) == 2 ? 'Test' : $matches[0];
},
$text
);
If you wish to keep the text inside ** as is and make it bold, you can capture it in a group and surround it with bold tags.
Snippet:
<?php
$newText = preg_replace_callback(
'/([*] )([^*] )([*] )/',
function ($matches) {
return strlen($matches[1]) == 2 && strlen($matches[3]) == 2 ? '<b>' . $matches[2] . '</b>' : $matches[0];
},
$text
);
CodePudding user response:
You can do it with a handful of zero-length assertions. This is the regex that I suggest: (?<!\*)\*{2}(?!\*).*?(?<!\*)(?<!\*)\*{2}(?!\*) You can play with this here.
Explanation:
(?<!\*)A negative lookbehind: the match must not be preceded with a star character. It can be preceded with any other character, as well as with the line start. For the record,^is a well-known zero-length assertion.\*{2}- matches two stars(?!\*)- negative lookahead. This means that the next character must not be a star. However, this is a zero-length assertion, so the next character will not be matched..*?- everything else - the star is for the non-greedy match. Not necessary, but I find it enhances the regex match. You can also group this if you want to do something with the match later.(?<!\*)- negative lookbehind - another zero-length assertion. It specifies that the last character must not be a star.\*{2}- two stars, to close the match(?!\*)- A negative lookahead: the match must not be followed by a star. It can be any other character, as well as the end of line. Btw,$is a well-known zero-length assertion.
