The normal workaround for the lookbehind deficit is to use a callback function
in the replace part.
The reason is that you have to match the errant part just to move the match position
past it. This requires logic in a callback function.
In %99.99 of the cases, you will have to do it this way if you have different replacements.
For the case you have it doesn't matter because you have a single replacement that is blank.
It gets masked by a combined group replacement where the stripping is controlled by
not having it in a group.
If you were to replace it with anything other than the empty string,
this is the only way to do it.
To that end, here is your (mostly) unaltered regex used with a callback.
( # (1 start)
(?: ^ [\w\d\-.]{2,} : | ^ | \? .* )
//
) # (1 end)
| /
(?= / )
var urls = [
'https://asdf.com//asdf//asdf',
'http://asdf.com//asdf//asdf',
'ftp://asdf.com//asdf//asdf',
'//asdf.com//asdf//asdf',
'//asdf.com//asdf//asdf?test=//',
'z39.50s://asdf//' ];
for (var i = 0; i < urls.length; i++)
{
urls[i] = urls[i].replace(
/((?:^[\w\d\-.]{2,}:|^|\?.*)\/\/)|\/(?=\/)/gm,
function(match, Grp1)
{
if ( Grp1 )
return Grp1;
return '';
}
);
}
console.log( urls );