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_callback
to check with the captured groups and returnTest
accordingly 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.