Google Apps Script: RegExp g Modifier - google-apps-script

I can't seem to get the "g modifier" in a RegExp to work in a Google script.
When I try to apply it, sometimes I get the error that "ReferenceError: "g" is not defined.". When I remove the /g both regExp.exec and input.match(regExp) work, but only for the first match. Other times, I'll get the /g to work, but it returns null, not even producing the first match. I had attempted a while loop, but I didn't want to slow down this process even more (I'll save optimizing this script for another post once I get it to work as intended).
The short version is, I'm trying to get ALL matches (email addresses) not just the first one. Where do I apply the /g? Should I use another method?
You can see (below) what I've been attempting below.
Any tips? I appreciate any help me understand this and anyone that can show me a better way to approach this. Thanks!
if (colA != "" && colE != processed) {
var html = UrlFetchApp.fetch(colA).getContentText();
//Logger.log(html);
var regExp = new RegExp("[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]{2,4}");
var regExp2 = new RegExp("[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]{2,4}");
var regExp3 = '[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]/g {2,4}';
var regExp4 = '[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]{2,4}/g';
var extractTest = html.match(regExp3);
//var extract = regExp.exec(html);
Logger.log(extractTest);
}
You can see the "bigger picture" of it all below.
//TEST
var processed = "YES";
function test() {
var ss = SpreadsheetApp.openById('1E4yUVIpwi00DzjfnXrZSgNFmVjOQbNWewxAiTBHRdD4');
var sheet = ss.getSheetByName('Sheet5');
var currentRow = 2;
var currentColumn = 1;
var numRows = sheet.getLastRow()-1;
var numColumns = 5;
var range = sheet.getRange(currentRow, currentColumn, numRows, numColumns);
var values = range.getValues();
//Logger.log(values);
for (var i = 0; i < numRows; ++i) {
var column = values[i];
var colA = column[0];
var colB = column[1];
var colC = column[2];
var colD = column[3];
var colE = column[4];
if (colA != "" && colE != processed) {
var html = UrlFetchApp.fetch(colA).getContentText();
//Logger.log(html);
var regExp = new RegExp("[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]{2,4}");
var regExp2 = new RegExp("[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]{2,4}");
var regExp3 = '[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]/g {2,4}';
var regExp4 = '[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]{2,4}/g';
var extractTest = html.match(regExp3);
//var extract = regExp.exec(html);
Logger.log(extractTest);
}
}
//var destRange = sheet.getRange(currentRow+i,2);
//destRange.setValue(extract);
//var destRange2 = sheet.getRange(currentRow+i,5);
//destRange2.setValue(processed);
SpreadsheetApp.flush();
}

Using the solution provided by #I'-'I (see comments above): var re = /[A-z0-9._%+-]+#[A-z0-9.-]+\.[A-z]{2,4}/g;

Related

Data validation Script loop

I have a code to create a data validation on a cell from a range next to it.
example:
var cellC4 = cell.getRange('F11');
var range = SpreadsheetApp.getActive().getRange('MAIN!AG11:AG11');
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cellC4.setDataValidation(rule);
var cellC5 = cell.getRange('F12');
var range = SpreadsheetApp.getActive().getRange('MAIN!AG12:AG12');
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cellC5.setDataValidation(rule);
var cellC6 = cell.getRange('F13');
var range = SpreadsheetApp.getActive().getRange('MAIN!AG13:AG13');
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cellC6.setDataValidation(rule);
var cellC7 = cell.getRange('F14');
var range = SpreadsheetApp.getActive().getRange('MAIN!AG14:AG14');
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cellC7.setDataValidation(rule);
can someone help me do it correctly
Im stuck here:
function onOpen(){
var ss0 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('MAIN');
var EndRow = ss0.getLastRow();
for ( var c = 16;c <= 25; c) {
for ( var i = 11;i <= EndRow; i++ ) {
//►PO# VALIDATION►
var range1 = ss0.getRange(i, c);
var rule1 = SpreadsheetApp.newDataValidation().requireValueInRange(range1).build();
ss0.getRange(i, 5).setDataValidation(rule1);
}}}
Findings:
Your looping for this part for ( var c = 16;c <= 25; c) { has a
wrong iteration with c instead of using c++. Thus, this looping
will never finish running.
SUGGESTION:
==UPDATE===
You can try this sample script below:
function onOpen(){
var ss0 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('MAIN');
var EndRow = ss0.getLastRow();
for(row=11; row<=EndRow; row++){
var data = ss0.getRange("P"+row+":Y"+row).getDisplayValues();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(data[0]).build();
ss0.getRange(row,5).setDataValidation(rule);
}
}
Sample:
Result on column 5 or column E after the onOpen() function finishes running

Double the variables in move script (Google)

For my work I am trying to automatically move a marked line to a 'Historie' sheet. I have currently managed to follow an example and use 1 variable (see copy).
Now I want 2 variables. Instead of just column K -> Completed, I also want to add that column J needs to be True!
function onEdit(event){
var url = "https://docs.google.com/spreadsheets/d/1per7L2wPkMKrzVgv5npQ-2RQ8fkWzslo09Ntlzy4qAs/edit?ts=6034e66e#gid=0";
var source_sheet_name = "Werklijst";
var target_sheet_name = "Historie";
var columnLetter = "J";
var ss= SpreadsheetApp.openByUrl(url);
var source_sheet = ss.getSheetByName(source_sheet_name);
var target_sheet = ss.getSheetByName(target_sheet_name);
var source_range = source_sheet.getRange(columnLetter+":"+columnLetter).getValues();
for(var i = source_range.length-1; i >= 0;i--){
if(source_range[i]=="COMPLETE"){
var targetRange = target_sheet.getRange(target_sheet.getLastRow() + 1, 1);
source_sheet.getRange((i+1), 1, 1, source_sheet.getLastColumn()).moveTo(targetRange);
source_sheet.deleteRow((i+1));
}
}
}
Here is the link to a copy of said sheet (it is in Dutch).
The obvious solution would be to do something like that:
var columnLetter1 = "K";
var columnLetter2 = "J";
var source_range1 = source_sheet.getRange(columnLetter1+":"+columnLetter1).getValues();
var source_range2 = source_sheet.getRange(columnLetter2+":"+columnLetter2).getValues();
and then change the if statement to:
if(source_range1[i]=="COMPLETE" && source_range2[i]==true)
Full snippet of the user's code with the modification points:
function onEdit(event){
var url = "https://docs.google.com/spreadsheets/d/1per7L2wPkMKrzVgv5npQ-2RQ8fkWzslo09Ntlzy4qAs/edit?ts=6034e66e#gid=0";
var source_sheet_name = "Werklijst";
var target_sheet_name = "Historie";
var columnLetter1 = "K";
var columnLetter2 = "J";
var ss= SpreadsheetApp.openByUrl(url);
var source_sheet = ss.getSheetByName(source_sheet_name);
var target_sheet = ss.getSheetByName(target_sheet_name);
var source_range1 = source_sheet.getRange(columnLetter1+":"+columnLetter1).getValues();
var source_range2 = source_sheet.getRange(columnLetter2+":"+columnLetter2).getValues();
for(var i = source_range.length-1; i >= 0;i--){
if(source_range1[i]=="COMPLETE" && source_range2[i]==true){
var targetRange = target_sheet.getRange(target_sheet.getLastRow() + 1, 1);
source_sheet.getRange((i+1), 1, 1, source_sheet.getLastColumn()).moveTo(targetRange);
source_sheet.deleteRow((i+1));
}
}
}
Keep in mind that the current code is not very optimal since you don't use the event object anywhere in your code. The latter will help you get info regarding the edits.
For example, right now your whole code will be executed upon every edit in any cell in the entire spreadsheet file. If you use the event object you can execute some code upon edits on a particular sheet (e.g. Werklijst) and on particular cells (e.g. cells in column K or J). In this way your code will be way faster and more efficient.

Google Docs Script: appendText/insertText Formatting

How do I use appendText() or insertText() for a Google Doc script and maintain formatting?
I want to format the middle portion (group2) of appended strings with italics, while leaving the other parts (group1, group3) as normal text. For example: Hi my name is Nate.
I can bring in "Hi" and append "my name is" and it formats correctly. When I try to append (or insert) "Nate," "Nate" is italicized as well.Between operators +, appendText(), and insertText(), I'm not having much luck.
Below is the relevant portion of the script. Below that, is the entire thing.
How can I append 3 strings together, and only format the middle portion?
NOTE: I commented-out the things I tried (trial1, trial2, etc.). I also started HERE and used it as a guide.
Thanks for any help you can offer!
RELEVANT PART:
if (author1 != "") {
var group1 = author1+author2+author3;
var group2 = title2Italics+containerItalics;
var group3 = contribution1+contribution2+contribution3+version+number+publisher+pubDate+location;
//Only using the calculations below to determine the offset for insertText
var group1Length = group1.length;
var group2Length = group2.length;
var offset = group1Length+group2Length
Logger.log(group1Length);
Logger.log(group2Length);
Logger.log(offset);
//Determines if italicizing is necessary
if (group2.length > 0) {
var addG1 = body.insertParagraph(0,group1)
var addG2 = addG1.appendText(group2);
var formatItalics = addG2.editAsText().setItalic(true);
//var trial1 = addG2.editAsText().setItalic(true) + group3; //does not return the contents of "group3"
//var trial2 = formatItalics + group3; //does not return the contents of "group3"
//var trial3 = formatItalics.insertText(offset,group3); //Error: "Index (18) must be less than or equal to the content length (6)."
//var trial4 = formatItalics.insertText(group2Length, group3); //formats "group3" as well
//var trial5 = formatItalics.appendText(group3); //formats "group3" as well
}
//If italicizing is NOT necessary
else {
var cite = body.insertParagraph(0,group1 + group3);
} //ELSE STATEMENT ENDS HERE
} //FIRST IF STATEMENT ENDS HERE
ENTIRE SCRIPT:
function mlaBibTest() {
// Sheet Information
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName('test'));
var startRow = 3;
var startCol = 21;
var numRows = sheet.getLastRow()-1;
var numCols = 14;
var dataRange = sheet.getRange(startRow, startCol, numRows, numCols);
// Document information
var doc = DocumentApp.openById('13MlHq_uoO1rUF0RfdF_kBlLJjbGt4aDoOcSWef0V4zM');
var body = doc.getBody();
// Fetch values for each row in the SS Range.
var cells = dataRange.getValues();
for (var i = 0; i < cells.length; ++i) {
var column = cells[i];
var colU = column[0];
var colV = column[1];
var colW = column[2];
var colX = column[3];
var colY = column[4];
var colZ = column[5];
var colAA = column[6];
var colAB = column[7];
var colAC = column[8];
var colAD = column[9];
var colAE = column[10];
var colAF = column[11];
var colAG = column[12];
var colAH = column[13];
var author1 = colU;
var author2 = colV;
var author3 = colW;
var title1Quotes = colX;
var title2Italics = colY;
var containerItalics = colZ;
var contribution1 = colAA;
var contribution2 = colAB;
var contribution3 = colAC;
var version = colAD;
var number = colAE;
var publisher = colAF;
var pubDate = colAG;
var location = colAH;
if (author1 != "") {
var group1 = author1+author2+author3;
var group2 = title2Italics+containerItalics;
var group3 = contribution1+contribution2+contribution3+version+number+publisher+pubDate+location;
//Only using the calculations below to determine the offset for insertText
var group1Length = group1.length;
var group2Length = group2.length;
var offset = group1Length+group2Length
Logger.log(group1Length);
Logger.log(group2Length);
Logger.log(offset);
//Determines if italicizing is necessary
if (group2.length > 0) {
var addG1 = body.insertParagraph(0,group1)
var addG2 = addG1.appendText(group2);
var formatItalics = addG2.editAsText().setItalic(true);
//var trial1 = addG2.editAsText().setItalic(true) + group3; //does not return the contents of "group3"
//var trial2 = formatItalics + group3; //does not return the contents of "group3"
//var trial3 = formatItalics.insertText(offset,group3); //Error: "Index (18) must be less than or equal to the content length (6)."
//var trial4 = formatItalics.insertText(group2Length, group3); //formats "group3" as well
//var trial5 = formatItalics.appendText(group3); //formats "group3" as well
}
//If italicizing is NOT necessary
else {
var cite = body.insertParagraph(0,group1 + group3);
} //ELSE STATEMENT ENDS HERE
} //FIRST IF STATEMENT ENDS HERE
} //FOR LOOP ENDS HERE
SpreadsheetApp.flush();
} // FUNCTION ENDS HERE
This is a simple example of doing what you asked. It's important to remember that setItalics(true) sets a persistent setting for all new text to be italic, so we have to set it back to false after.
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var paragraph = body.insertParagraph(0, ""); //add paragparh at top of body.
var text1 = paragraph.appendText("Not Italics ");
var text2 = paragraph.appendText("Italics ");
text2.setItalic(true); //Everything after and including this will be italics
var text3 = paragraph.appendText("Not Italics");
text3.setItalic(false); //Everything after and including this will not be italics
>Not Italics Italics Not Italics
So it's easier if you set italics as you build the paragraph.

Method is heavily used by the script

I am very new on using Google Apps Script and has a shallow knowledge on programming. What I am trying to do is copy the values of specific columns to a different Spreadsheet. Here's my code:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var responses = ss.getSheetByName("Responses ID");//Where ID's of the spreadsheets are listed.
var consolidatedSheet = ss.getSheetByName("Consolidated");//Where the data should be pasted.
var responseColValues = responses.getRange(2,2, responses.getMaxRows() -1).getValues();
var responsesIds = [i for each (i in responseColValues)if (isNaN(i))];
var ssSelected = SpreadsheetApp.openById(responsesIds[0]);
var selectedSheets = ssSelected.getSheets();
for (i=0; i<3; i++){
var maxRows = selectedSheets[i].getLastRow()-1;
var x=2, y=2;
var lastRow = consolidatedSheet.getLastRow()+1;
for (j=0; j<maxRows; j++){
var eventID = selectedSheets[i].getRange(y,2).getValue();
var employeeName = selectedSheets[i].getRange(y,3).getValue();
var productionDate = selectedSheets[i].getRange(y,4).getValue();
var consolidatedSheetCell = consolidatedSheet.getRange(lastRow,1).setValue(eventID);
var consolidatedSheetCell = consolidatedSheet.getRange(lastRow,2).setValue(employeeName);
var consolidatedSheetCell = consolidatedSheet.getRange(lastRow,3).setValue(productionDate);
y++;
lastRow++;
}
}
}
However, I am experiencing this notification on the Execution hints (light bulb icon):
screenshot of the message. I am thinking that my code can be simplified. I am just not sure how to do it. Thank you in advance.
Every line with .getRange().getValue() and getRange.setValue() is a call to the file. Since you have these inside a for(){} loop, they are being called many times. Your goal is to limit these to as few as possible. Since you can read and write a range, you could do something similar to this:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var responses = ss.getSheetByName("Responses ID");//Where ID's of the spreadsheets are listed.
var consolidatedSheet = ss.getSheetByName("Consolidated");//Where the data should be pasted.
var responseColValues = responses.getRange(2,2, responses.getMaxRows() -1).getValues();
var responsesIds = [i for each (i in responseColValues)if (isNaN(i))];
var ssSelected = SpreadsheetApp.openById(responsesIds[0]);
var selectedSheets = ssSelected.getSheets();
for (i=0; i<3; i++){
var maxRows = selectedSheets[i].getLastRow()-1;
var y=2;
var lastRow = consolidatedSheet.getLastRow()+1;
var copyValues = selectedSheets[i].getRange(y,2, maxRows, 4).getValues();
consolidatedSheet.getRange(lastRow,1, maxRows, 4).setValues(copyValues);
}
}

Google Apps Script: Function to update names from one sheet to another times out. Please refine my loops

I have an app through google docs that I use to record student attendance to my after school tutoring center. I have had higher than usual attendance and my code is not efficient enough to run before timing out. Please assist me in editing my code so that it runs more effectively.
I have to note that I am an absolute beginner, so if this is inappropriately posted, please give me constructive feedback on how to get help with this problem. And I apologize in advance for the (I assume) horrible code you are about to see - it's the best I could do and I worked very hard to create this.
Thank you.
Code:
function updateAttendance(){
var itemSpreadsheetKey = '';
var openedSS = SpreadsheetApp.openById(itemSpreadsheetKey);
var sheetStudentNames = openedSS.getSheetByName("StudentNames");
var sheetDailyData = openedSS.getSheetByName("DailyData");
var app = UiApp.getActiveApplication();
var ss = SpreadsheetApp.openById(itemSpreadsheetKey);
var dailyDataSheet = ss.getSheetByName("DailyData");
var studentNameSheet = ss.getSheetByName("StudentNames");
var dailyData = dailyDataSheet.getDataRange();
var studentNames = studentNameSheet.getDataRange();
var dailyLastRow = dailyData.getLastRow();
var studentNamesLastRow = studentNames.getLastRow();
var studentNamesLastColumn = studentNames.getLastColumn();
var dailyDataNamesArray = sheetDailyData.getRange(2, 1, dailyLastRow).getValues();
for (var i=1; i<=dailyDataNamesArray.length; i++) {
if (i != ""){
var dailyTime = dailyData.getCell(i, 5).getValue();
for (var j=2; j<=studentNamesLastRow; j++) {
var today = dailyData.getCell(1, 8).getValue();
if (dailyData.getCell(i, 1).getValue() == studentNames.getCell(j, 1).getValue()) {
studentNames.getCell(1, studentNamesLastColumn).offset(0, 1).setValue(today);
studentNames.getCell(j, studentNamesLastColumn).offset(0, 1).setValue(dailyTime);
}
}
}
}
return app;
}
If you want your script to go faster you must use array manipulation instead of all these range.setValue() .
Change all the values in a global array (a pair of actually) and when you're done just write these arrays to their respective sheets.
The difference will be enormous ! believe me ;)
All this is pretty well explained in the documentation about best practices.
Here is a "translation" of your code, I'm not sure I didn't make any error in transposition but I have no way to check without knowing what is in your sheets.
Just remember that arrays are 0 indexed while ranges start at 1.
function updateAttendance(){
var itemSpreadsheetKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx';
var openedSS = SpreadsheetApp.openById(itemSpreadsheetKey);
var sheetStudentNames = openedSS.getSheetByName("StudentNames");
var sheetDailyData = openedSS.getSheetByName("DailyData");
var app = UiApp.getActiveApplication();
var ss = SpreadsheetApp.openById(itemSpreadsheetKey);
var dailyDataSheet = ss.getSheetByName("DailyData");
var studentNameSheet = ss.getSheetByName("StudentNames");
var dailyData = dailyDataSheet.getDataRange();
var studentNames = studentNameSheet.getDataRange().getValues();
var dailyLastRow = dailyData.getLastRow();
var studentNamesLastRow = studentNames.getLastRow();
var studentNamesLastColumn = studentNames.getLastColumn();
var dailyDataNamesArray = sheetDailyData.getDataRange().getValues();
for (var i = 1 ; i < dailyDataNamesArray.length; i++) {
if (i != ""){
var dailyTime = dailyDataNamesArray[i][4];
for (var j=1; j<studentNamesLastRow; j++) {
var today = dailyDataNamesArray[0][7];
if (dailyDataNamesArray[i][0] == studentNames[i][0]) {
studentNames[0][studentNamesLastColumn+1] = today;
studentNames[j][studentNamesLastColumn+1] = dailyTime;
}
}
}
}
studentNameSheet.getRange(1,1,studentNames.length,studentNames[0].length).setValues(studentNames):
dailyDataSheet.getRange(1,1,dailyDataNamesArray.length,dailyDataNamesArray[0].length).setValues(dailyDataNamesArray):
return app;
}
Replace the code after the var dailyDataNamesArray line with the following. It's a bit of a guess, so I hope for you that it works:
var todayCell1 = studentNames.getCell(1, studentNamesLastColumn).offset(0, 1);
for (var i=1; i<=dailyDataNamesArray.length; i++) {
if (i != ""){
var dailyTime = dailyData.getCell(i, 5).getValue();
var dailyVar2 = dailyData.getCell(i, 1).getValue();
for (var j=2; j<=studentNamesLastRow; j++) {
var today = dailyData.getCell(1, 8).getValue();
if ( dailyVar2 == studentNames.getCell(j, 1).getValue()) {
todayCell1.setValue(today);
studentNames.getCell(j, studentNamesLastColumn).offset(0, 1).setValue(dailyTime);
}
}
}
}