Alex Turpin Alex Turpin - 3 months ago 11
Javascript Question

Making part of JavaScript regex optional

I have the following original strings:

# Original strings
js/main_dev.js # This one is just to check for false positives
js/blog/foo.js
js/blog/foo.min.js


I'd like to run a substitution regex on each one and end up with this:

# Desired result
js/main_dev.js
js/blog/foo_dev.js
js/blog/foo_dev.min.js


So basically, add
_dev
before
.min.js
if it exists, if not, before
.js
. That should only apply on strings that start with
js/blog
or
js/calculator
and end in
.js
.

I initially started out with
(js\/(?:blog|calculators)\/.+)(\.min\.js)$
as a regex and then
$1_dev$2
as substitution. That works for my third string, but not my second obviously as I am "hard" looking for
.min.js
. So I figured I'd make
.min
optional by throwing it in a non capture group with a
?
like this:
(js\/(?:blog|calculators)\/.+)((?:\.min)?\.js)$
. Now this works for my second string but my third string is all out of whack:

js/main_dev.js # Good
js/blog/foo_dev.js # Good
js/blog/foo.min_dev.js # Bad! _dev should be before the .min


I've tried many permutations on this, including simply doing
(\.min\.js|\.js)
but to no avail, all result in the same behavior. Here is a Regex 101 paste with the "bad" regex: https://regex101.com/r/bH3yP6/1

What am I doing wrong here?

Answer

Try throwing a ? after the + at the end of your first group (the non-capturing one) to make it non-greedy:

(js\/(?:blog|calculators)\/.+?)((?:\.min)?\.js)$

This seemed to fix the issue in the regex101 link you provided. Because (?:\.min)? is optional and .+ is greedy, .+ was capturing the .min.

https://regex101.com/r/bH3yP6/3