How can I replace all internal urls in a string of html with their relative external url?

Viewed 179

Given a string of html like the one below:

<html>
<link rel="stylesheet" href="/thing.css">

<body>
    <script src="/nothing.js"></script>
    <link rel="stylesheet" href="/styles.css">
    <a href='#a_hash'>A link</a>
</body>

</html>

I want to be able to get the following:

<html>
<link rel="stylesheet" href="//example.com/thing.css">

<body>
    <script src="//example.com/nothing.js"></script>
    <link rel="stylesheet" href="//example.com/styles.css">
    <a href='//example.com#a_hash'>A link</a>
</body>

</html>

And I preferably need to do this without a library, and in vanilla JavaScript. Currently I have this regex to find urls (I'm open to new ones!):

<.+?(?:href|src)=(?:"|')([^"']+)(?:"|').*?>
2 Answers

Use

.replace(/\b((?:href|src)=)(?!\/\/example\.com)(["']?)([^"']+)\2/gi, 
   (_,x,y,z) => z.charAt(0) == '/' ? 
   `${x}${y}//example.com${z}${y}` : `${x}${y}//example.com/${z}${y}`)

See regex proof.

Explanation

--------------------------------------------------------------------------------
  \b                       the boundary between a word char (\w) and
                           something that is not a word char
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    (?:                      group, but do not capture:
--------------------------------------------------------------------------------
      href                     'href'
--------------------------------------------------------------------------------
     |                        OR
--------------------------------------------------------------------------------
      src                      'src'
--------------------------------------------------------------------------------
    )                        end of grouping
--------------------------------------------------------------------------------
    =                        '='
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    \/                       '/'
--------------------------------------------------------------------------------
    \/                       '/'
--------------------------------------------------------------------------------
    example                  'example'
--------------------------------------------------------------------------------
    \.                       '.'
--------------------------------------------------------------------------------
    com                      'com'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (                        group and capture to \2:
--------------------------------------------------------------------------------
    ["']?                    any character of: '"', ''' (optional
                             (matching the most amount possible))
--------------------------------------------------------------------------------
  )                        end of \2
--------------------------------------------------------------------------------
  (                        group and capture to \3:
--------------------------------------------------------------------------------
    [^"']+                   any character except: '"', ''' (1 or
                             more times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
  )                        end of \3
--------------------------------------------------------------------------------
  \2                       what was matched by capture \2

const string = ' href="nowhere"  src="/nothing.js"';
const rx = /\b((?:href|src)=)(?!\/\/example\.com)(["']?)([^"']+)\2/gi;
console.log(string.replace(rx, (_,x,y,z) => z.charAt(0) == '/' ? 
   `${x}${y}//example.com${z}${y}` : `${x}${y}//example.com/${z}${y}`));

Related