Remove URLs from text with regex, except current domain

Viewed 207

I'm trying to preg replace a string and remove from it all URLs which do not contain current domain.

So far I got this regex, but it does not exclude mydomain. What I'm doing wrong?
http[s]?:\/\/[w]{0,3}\.{0,1}((?<!mydomain)[^\.].*)

Expected input and output:
http://regex101. => should match
http://www.regex101. => should match
https://regex101. => should match
https://www.regex101. => should match
https://www.mydomain. => should not match, but it does

https://regex101.com/r/kGil9O/1

I've read several SO questions/answers and either they don't work for my case, either are somehow different. When answer, please explain where I was wrong so I could be better next time. Thanks!

2 Answers

You get all the matches with the pattern that you tried, as the negative lookbehind asserts if mydomain is not directly to the left after matching for example https:// or https://www which is always true.

You can optionally match www\. using a possessive quantifier followed by a negative lookahead:

^https?://(?:www\.)?+(?!mydomain\.)\S+$

The pattern matches:

  • ^ Start of string
  • https?:// Match the protocol with optional s and ://
  • (?:www\.)?+ Optionally match www. and use a possessive quantifier to not backtrack when matched
  • (?!mydomain\.) Negative lookahead, assert not mydomain. directly at the right from the current position
  • \S+ Match 1+ times any non whitspace char
  • $ End of string

regex demo | Php demo

Example

$strings = [
    "http://regex101.",
    "http://www.regex101.",
    "https://regex101.",
    "https://www.regex101.",
    "https://www.mydomain.",
    "https://mydomain."
];
$pattern = "~^https?://(?:www\.)?+(?!mydomain\.)\S+$~";
foreach ($strings as $s) {
    if (preg_match($pattern, $s)) {
        echo "Match: $s" . PHP_EOL;
    } else {
        echo "No match: $s" . PHP_EOL;
    }
}

Output

Match: http://regex101.
Match: http://www.regex101.
Match: https://regex101.
Match: https://www.regex101.
No match: https://www.mydomain.
No match: https://mydomain.

You use the lookbehind in a wrong way, it checks the text on the left, and you try to match www. before the lookbehind. www. is not mydomain.

Use a lookahead:

https?:\/\/(?!(?:www\.)?mydomain)(?:www\.)?([^.].*)

See proof

EXPLANATION

--------------------------------------------------------------------------------
  http                     'http'
--------------------------------------------------------------------------------
  s?                       's' (optional (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  :                        ':'
--------------------------------------------------------------------------------
  \/                       '/'
--------------------------------------------------------------------------------
  \/                       '/'
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    (?:                      group, but do not capture (optional
                             (matching the most amount possible)):
--------------------------------------------------------------------------------
      www                      'www'
--------------------------------------------------------------------------------
      \.                       '.'
--------------------------------------------------------------------------------
    )?                       end of grouping
--------------------------------------------------------------------------------
    mydomain                 'mydomain'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (?:                      group, but do not capture (optional
                           (matching the most amount possible)):
--------------------------------------------------------------------------------
    www                      'www'
--------------------------------------------------------------------------------
    \.                       '.'
--------------------------------------------------------------------------------
  )?                       end of grouping
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    [^.]                     any character except: '.'
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
  )                        end of \1
Related