Home > Mobile >  regex selects zero prefix to avoid negative lookahead
regex selects zero prefix to avoid negative lookahead

Time:10-14

I have (hopefully) the full example here: https://www.phpliveregex.com/p/Cfh

I need to add absolute paths to css url with relative path. (I'm merging several css files in different locations, so relative paths to the original location doesn't work)

For instance

background-image: url("star.gif"); -> background-image: url("/images/star.gif");

But not background-image: url(https://example.com/images/star.gif);

I'm using preg_replace('/url\((["\']?)(?!(\/|http(s)?:|data:|#))(.*?)\1\)/mi', 'url("/images/$4")', $input_lines);

An url can be sourrounded by 0 or 1 single or double quotes, but they must be balanced. (["']?) ... \1

url should not start with / http(s): data: or # (?!(\/|http(s)?:|data:|#))

But url("https://www.example.com/style.css") gets turned into url("/images/"https://www.example.com/style.css"");

because regex selects zero quotes, so "https: doesn't match http(s)?:

Without quotes the rexex doesn't match, which is good. url(https://example.com/images/star.gif);

Is there a way to stop trying to match if a negative lookahead has given a match?

CodePudding user response:

In addition to the "probably-good-enough" solution in the comment (because most URLs don't contain quotes), here's two more correct solutions, with a caveat that they use features that are not available in every regexp dialect.

You can say "once I've found whether or not there is a quote, I will not change my mind" using {*PRUNE} (disallowing any backtracking to its left):

url\((["']?){*PRUNE}(?!(\/|http(s)?:|data:|#))(.*?)\1\)

or using atomic groups (locking in that one decision):

url\(((?>["']?))(?!(\/|http(s)?:|data:|#))(.*?)\1\)
  • Related