Search code examples
regexgoogle-apps-scriptparentheses

How to embolden specific text within multiple instances of parentheses in Google Apps Script?


I've been trying to write a Google Apps Script to search a document and change all instances of a parenthesis(including the parentheses themselves) from this:

Hello (C)world, nice to (D)meet you, You are (G) my sunshine, my (Em)only sunshine.

To this:

Hello **(C)**world, nice to **(D)**meet you, You are **(G)** my sunshine, my **(Em)** only sunshine.

I've done it successfully like so:

function onOpen() {
  DocumentApp.getUi()
      .createMenu('Utilities')
      .addItem('Bold Parentheses', 'replaceParentheses')
      .addToUi();
};

function replaceParentheses() {
  var body = DocumentApp.getActiveDocument().getBody();      

  var found = body.findText("\\(.+?\\)");
  while (found) {
    var elem = found.getElement();
    if (found.isPartial()) {
      var start = found.getStartOffset();
      var end = found.getEndOffsetInclusive();
      elem.setBold(start, end, true);
    }
    else {
      elem.setBold(true);
    }
    found = body.findText("\\(.+?\\)", found);
  }
};

But am wondering if there is a more efficient way to do this.

I am using this to embolden chord names in the parenthesis... so if there was a call and response in the lyrics and some lyrics had parenthesis around them - how would I exclude those parenthesis in this? In other words, how could I make a set of variables to always bolden like (A,B,C,A#,B#,C#,Ab,Bb,Cb,Am,Bm,Cm,Adim7,Bb7add9, etc)


Solution

  • Your code works fine to bold everything inside a parenthesis. But if you want to set a list of variables that should be bolded and forget about the rest you could try to create and array and plug it in the regEx.

    You could change your code like so:

    function replaceParentheses() {
      var body = DocumentApp.getActiveDocument().getBody();  
      var targetVariables = ['A', 'B', 'C', 'A#']
    
      var searchPattern = "\\([" + targetVariables.join("|") + "].?\\)"
    
    
      var found = body.findText(searchPattern);
      while (found) {
        var elem = found.getElement();
        if (found.isPartial()) {
          var start = found.getStartOffset();
          var end = found.getEndOffsetInclusive();
          elem.setBold(start, end, true);
    
        }
        else {
          elem.setBold(true);
        }
        found = body.findText(searchPattern, found);
      }
    };
    

    Take into consideration that now you only match with values that are inside of targetVariables, so for example:

    Hello (Caa)world (C) (A#), nice to (D)meet you, You are (G) my sunshine, my (Em)only sunshine.

    Would be conveted to:

    Hello (Caa)world (C) (A#), nice to (D)meet you, You are (G) my sunshine, my (Em)only sunshine.