简体   繁体   中英

Use RegEx to replace tags in document with column data from spreadsheet

I've been searching for the answer to this question but have so far been unable to piece together the answer. Please explain any answer you have in really simple terms as I'm fairly new to GAS and RegEx. I've got most of the syntax down but the execution of it in GAS is giving me a hard time.

Basically, I want to write a script that, when the spreadsheet is edited, checks which rows have yet to be merged. Then, on those rows, creates a copy of a template Google Doc and names the document based on the spreadsheet data. From there (this is the hard part), I need it to replace merge tags in the template with the data from the spreadsheet.

The tags in the templates I'll be using look like this: <<mergeTag>>

My idea was to match the whole tag, and replace it with data from the spreadsheet that exists in the column with the same name as what's inside the " <<>> ". Ex: <<FooBar>> would be replaced with the data from the column named FooBar . It would obviously be from the current row that needs the merging.

After that, all that's left is to send an email (a few more row-specific personalization) with that document attached (sometimes as a PDF) with the body of the message coming from an HTML file elsewhere in the project.

This is the whole thing I have so far (notice the placeholders here and there that I can personalize for each spreadsheet I use this for):

function onEdit() {
  //SPREADSHEET GLOBAL VARIABLES

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  //get only the merge sheet
  var sheet = ss.getSheetByName("Merge Data");
  //get all values for later reference
  var range = sheet.getActiveRange();
  var values = range.getValues();
  var lastRow = range.getLastRow();
  var lastColumn = range.getLastColumn();

  //get merge checker ranges
  var urlColumn = range.getLastColumn();
  var checkColumn = (urlColumn - 1);
  var checkRow = range.getLastRow();
  var checkRange = sheet.getRange(2, checkColumn, checkRow);
  var check = checkRange.getBackgrounds();

  //get template determination range (unique to each project)
  var tempConditionRange = sheet.getRange(row, column);
  var tempConditionCheck = tempConditionRange.getValues();

  //set color variables for status cell
  var red = "#FF0000";
  var yellow = "#FFCC00";
  var green = "#33CC33";

  //////////////////////////////////////////////////////////
  //DOC GLOBAL VARIABLES

  var docTemplate1 = DriveApp.getFileById(id);
  var docTemplate2 = DriveApp.getFileById(id);
  var docTemplate3 = DriveApp.getFileById(id);
  var folderDestination = DriveApp.getFolderById(id);

  //////////////////////////////////////////////////////////
  //EMAIL GLOBAL VARIABLES
  var emailTag = ss.getRangeByName("Merge Data!EmailTag");
  var personalizers = "";
  var subject = "" + personalizers;
  var emailBody = HtmlService.createHtmlOutputFromFile("Email Template");

  //////////////////////////////////////////////////////////
  // MERGE CODE

  for (i = 0; i < check.length; i++) {
    //for rows with data, check if they have already been merged
    if (check[i] == green) {
       continue;
    } else {
      var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
      var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
      var dataRow = sheet.getRange((i+2), 1, lastRow, (lastColumn - 2))
      statusCell.setBackground(red);
      //for rows with data, but not yet merged, perform the merge code

  //////////////////////////////////////////////////////////
  //DOC CREATION

  //Determine which template to use
  if (tempConditionCheck[i] == "") {
    var docToUse = docTemplate1;
  }
  if (tempConditionCheck[i] == "") {
    var docToUse = docTemplate2;
  }
  if (tempConditionCheck[i] == "") {
    var docToUse = docTemplate3;
  }

  //Create a copy of the template
  //Rename the document using data from specific columns, at specific rows
  //Move the doc to the correct folder
  var docName = "";
  var docCopy = docToUse.makeCopy(docName, folderDestination);
  var docId = docCopy.getId();
  var docURL = docCopy.getUrl();
  var docToSend = DriveApp.getFileById(docId);
  var docBody = DocumentApp.openById(docId).getBody();

Here's where I need the help

  //Locate the Merge Tags
  //Match Merge Tags to the column headers of the same name
  //Replace the Merge Tags with the data from the matched column, from the correct row
  function tagReplace() {
    var tagMatch = "/(<{2}(\w+)>{2})/g";
  }


  statusCell.setBackground(yellow);
  urlCell.setValue(docURL);

The rest is just finishing up the process

      //////////////////////////////////////////////////////////
      //EMAIL CREATION

      //Create an email using an HTML template
      //Use Merge Tags to personalize email
      //Attach the doc we created to the email
      //Send email to recipients based on data in the sheet
      MailApp.sendEmail(emailTag, subject, emailBody, {
        name: "Person McPerson",
        attachments: [docToSend], //[docToSend.getAs(MIME.PDF)],
        html: emailBody,
      });

      //////////////////////////////////////////////////////////
      //CHECK ROW UPDATE
      statusCell.setBackground(green);

    }
  }
}

My sheets all have a frozen first row that acts as the header row. All my columns will be consistently named the exact same thing as the tags (minus the <<>> ).

How do I match the tags to the data?

EDIT
```````````````````
The solution did not work as described when I inserted it into my code as follows:

function formMerge() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Merge Data");
  var urlColumn = sheet.getMaxColumns();
  var checkColumn = urlColumn - 1;
  var lastRow = ss.getSheetByName("Form Responses").getLastRow();
  var values = sheet.getDataRange().getValues();
  var headers = values[0];

  var urlRange = sheet.getRange(2, urlColumn, lastRow);
  var checkRange = sheet.getRange(2, checkColumn, lastRow);
  var check = checkRange.getBackgrounds();

  var red = "#ff0404";
  var yellow = "#ffec0a";
  var green = "#3bec3b";

  var docTemplate = DriveApp.getFileById(id);
  var folderDestination = DriveApp.getFolderById(id);

  // MERGE CODE
  for (i = 0; i < check.length; i++) {
    if (check[i] == green) {
      continue;
    } else {
      var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
      var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
      var dataRow = sheet.getRange((i+2), 1, 1, (urlColumn - 2)).getValues();
      var clientNameRange = sheet.getRange((i+2), 3);
      var clientName = clientNameRange.getValue();
      var dateRange = sheet.getRange((i+2), 2);
      var datePreFormat = dateRange.getValue();
      var timeZone = CalendarApp.getTimeZone();
      var date = Utilities.formatDate(new Date(datePreFormat), timeZone, "MM/dd/yyyy");
      statusCell.setBackground(red);

      //EMAIL VARIABLES
      var personalizers = clientName;
      var subject = "Post Intake Report for " + personalizers;
      var emailBody = "Please see the attached Google Doc for the Post Intake Report for " + clientName + ". The intake was performed on " + date + ".";
      var emailTagRange = sheet.getRange((i+2), 24);
      var emailTagValue = emailTagRange.getValue();
      var emailTag = emailTagValue.split(", ");

      //DOC CREATION
      var docToUse = docTemplate;
      var docName = "Post Intake Report - " + clientName + " [" + date + "]";
      var docCopy = docToUse.makeCopy(docName, folderDestination);
      var docId = docCopy.getId();
      var docURL = docCopy.getUrl();
      var docBody = DocumentApp.openById(docId).getBody().editAsText();

      for (var j=0; j<headers.length; j++) {
        var re = new RegExp("(<<"+headers[j]+">>)","g");
        docBody.replaceText(re, dataRow[j]);
      }
      statusCell.setBackground(yellow);
      urlCell.setValue(docURL);

      //EMAIL CREATION
      MailApp.sendEmail(emailTag, subject, emailBody, {
        name: "Christopher Anderson",
        attachments: [docCopy],
        html: emailBody
      });
      statusCell.setBackground(green);
    }
  }
}

Build the RegExp for each tag on the fly, using the header values from your spreadsheet. Use Body.replaceText() to perform the replacements.

var values = sheet.getDataRange().getValues();
var headers = values[0];

...

// Loop over all columns. Use header names to search for tags.
for (var col=0; col<headers.length; col++) {
  // Build RegExp using column header
  var re = new RegExp("(<{2}"+headers[col]+">{2})","g");
  // Replace tags with data from this column in dataRow
  body.replaceText(re, dataRow[col]);
}

This snippet will operate on a single row; the first couple of declarations should appear outside of your row loop. The column looping is then done after you've created and opened the new document, and obtained the body object.

It loops over all the columns in the spreadsheet, using the header names to find the tags you've defined, and replaces them with the corresponding cell contents for the current row.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM