Search code examples
javascriptgoogle-apps-scriptgoogle-docs

Google Apps Script search and replace URL truncates 1 character in rendered link


I'm using the code below to search for URLs in a Google Doc and turn them into active links. It works beautifully, except that the link cuts off the last character of the URL (e.g. "https://link.com/123" gets linked as "https://link.com/12").

function updateLinks() {
  var linkRegex = "https?:\/\/[^\\s]*";

  //Open active doc
  var body = DocumentApp.getActiveDocument().getBody();
  //Find URLs
  var link = body.findText(linkRegex);

  //Loop through the body finding texts matching the search pattern
  while (link != null) {
    // Get the link as an object
    var linkElement = link.getElement().asText();
    // Get the positions of start and end
    var start = link.getStartOffset();
    var end = link.getEndOffsetInclusive();
    //slice only the link out of it
    var correctLink = linkElement.getText().slice(start, end);

    // Format link
    linkElement.setLinkUrl(start, end, correctLink);
    // Find next
    link = body.findText(linkRegex, link);
  }
}

I'm sure this is simple, but I'm a complete novice and would appreciate any advice. Thanks in advance!


Solution

  • I thought that the reason of your issue is due to slice(start, end) of linkElement.getText().slice(start, end). In this case, it is required to be slice(start, end + 1). So, please modify it as follows and test it again.

    From:

    var correctLink = linkElement.getText().slice(start, end);
    

    To:

    var correctLink = linkElement.getText().slice(start, end + 1);
    

    Or, when you want to use linkRegex, how about the following modification?

    var correctLink = linkElement.getText().match(new RegExp(linkRegex))[0];
    

    Note:

    • As additional information, when the multiple URLs are included in a paragraph, I think that the following modification might be useful. Of course, in this modification, even when a single URL is included in a paragraph, the script works.

      • From

          var start = link.getStartOffset();
          var end = link.getEndOffsetInclusive();
          //slice only the link out of it
          var correctLink = linkElement.getText().slice(start, end);
        
          // Format link
          linkElement.setLinkUrl(start, end, correctLink);
        
      • To

          var text = linkElement.getText();
          var correctLinks = [...text.matchAll(new RegExp(linkRegex, "g"))];
          correctLinks.forEach(obj => linkElement.setLinkUrl(obj.index, obj.index + obj[0].length - 1, obj[0]));
        

    Reference: