Home > Blockchain >  Regex to only match two asterisks
Regex to only match two asterisks

Time:08-24

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 return Test 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
);

Online Demo


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
);

Online Demo

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.
  • Related