Validate phonenumbers to specific format using Google Sheet formula - google-apps-script

I'm working with google sheets and would like to convert US phone numbers to the format:
1xxxyyyzzzz
eg 402-333-4444 should be turned into 14023334444
I have an apps script validator function which does this:
var numbers = 'INVALID'
if ( parsed_body.hasOwnProperty('PHONE') ) {
var phone = parsed_body['PHONE'].toString();
Logger.log(parsed_body);
numbers = phone.replace(/[^0-9]/g, "");
var firstChar = numbers.charAt(0);
if ( firstChar !== '1'){ numbers = '1'+ numbers}
Logger.log(numbers);
if ( numbers.length !== 11){ numbers = 'NOTELEVEN'};
}
parsed_body['PHONE']=numbers;
but I'd like to make the sheet do this. Is this possible ?

It works out to quite a long formula if you do it in a single formula, because you have to keep repeating the previous steps, unlike in the script version:
=if(len(if(left(regexreplace(""&D2,"[^0-9]",""))="1","","1")&regexreplace(""&D2,"[^0-9]",""))=11,
if(left(regexreplace(""&D2,"[^0-9]",""))="1","","1")&regexreplace(""&D2,"[^0-9]",""),"INVALID")
May be changed to an array formula:
=ArrayFormula(if(D2:D="","",if(len(if(left(regexreplace(""&D2:D,"[^0-9]",""))="1","","1")&regexreplace(""&D2:D,"[^0-9]",""))=11,
if(left(regexreplace(""&D2:D,"[^0-9]",""))="1","","1")&regexreplace(""&D2:D,"[^0-9]",""),"INVALID")))

Related

How to replace part of a string using the slice method with an IF condition

I have the following script which is required to remove characters in a string leaving only the characters which follow the ">" character. For example, "GOOD > WEEKEND". When the script runs the output should be "WEEKEND". As there is one space after ">" i'm using slice(v.indexOf(">")+2)
The problem is everytime the script runs it removes another two more characters. To get round this I'm trying to include an if function so that the characters will only be removed if ">" is detected in the string with regex. Any help will be appreciated to get it to run successfully. An example can be viewed at https://docs.google.com/spreadsheets/d/1xBBbwA9j3mcR3iBTekGPGil92c6iInKyYXcq6NQpgpg/edit?usp=sharing
Thank you
function UpdateZoneRate(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('JOBS'); // adjust this to the name of your sheet
var zoneRate = sh.getRange('A2:A'+sh.getLastRow()).getValues();
for (var i=0;i<zoneRate.length;i++){
if (zoneRate[i][0].match(/([>])\w+/) )
var zoneValues = sh.getRange('A2:A'+sh.getLastRow()).getValues().flat().map(v=>[v.slice(v.indexOf(">")+2) || null])};
sh.getRange(2,53,zoneValues.length,1).setValues(zoneValues);
}
You can do that with a plain vanilla spreadsheet formula without resorting to scripting, like this:
=arrayformula( regexreplace(A2:A52, ".*> ?(.*)", "$1") )
To do the same with a script, try this:
function updateZoneRate() {
const range = SpreadsheetApp.getActive().getRange('JOBS!A2:A');
const zoneRate = range.getDisplayValues()
.flat()
.map(value => [value.replace(/.*> ?(.*)/, '$1')]);
range.offset(0, 1).setValues(zoneRate);
}

Converting Google Sheets IF formula to Apps script

As a test, I have entered the following formula in cell K2 of my spreadsheet: =IF($M2=today(),"Today"). This acheives the desired effect and I would like this to be applied to all the rows below (with m3 referring to k3 , m4 to k4 etc.) , HOWEVER, this sheet is updated via Google Form so I cannot leave a formula in these cells as it will be overwritten.
Therefore I need to write and run the formula in apps script but, whilst I have enough knowledge of script language to do write basic If functions, this one is beyond my skills.
I have referred to this: How to get range and then set value in Google Apps Script and tried to adapt it to my purposes but to no avail.
Could someone please enlighten me?
Try this script:
function isMToday() {
sheet = SpreadsheetApp.getActiveSheet();
lastRow = sheet.getLastRow();
// get M2:M range
mRange = sheet.getRange(2, 13, lastRow - 1, 1);
// get display values instead to avoid timezone issues
mValues = mRange.getDisplayValues();
today = new Date();
// check every mValue, if today, return today, else false
output = mValues.map(mValue => {
mValueDate = new Date(mValue);
if (mValueDate.getDate() == today.getDate() &&
mValueDate.getMonth() == today.getMonth() &&
mValueDate.getFullYear() == today.getFullYear())
return ["Today"];
else
return [false];
});
// write output to K2:K
mRange.offset(0, -2).setValues(output);
}
After execution:
You do not need AppScript to do this even though it is on a Form Responses tab.
Instead of this formula in cell K2 (as you described):
=IF($M2=today(),"Today")
Use this formula in cell K1, and delete all the other formulas in column K:
=ARRAYFORMULA(IF(ROW(M:M)=1,"Today?",IF(M:M=TODAY(),"Today")))

Finding and Deleting All Emojis in a Google Spreadsheet

I have a Google Spreadsheet with thousands of cells with each cell being populated with strings with many different emojis.
Example of entries:
"Lol ๐Ÿ˜Š","Haha ๐Ÿ˜Š","Fire ๐Ÿ”ฅ","๐Ÿ‘๐Ÿ‘๐Ÿ‘Awesome!","Nice๐Ÿ‘ See you tomorrow!๐Ÿ˜€",
"ใ“ใ‚“ใซใกใฏ๐Ÿ˜Š", "ไฝ ๅฅฝ๐Ÿ˜€"
But I want to delete all of the emojis, is there a search function I can run/piece of Spreadsheet code I can run to make the document devoid of emojis?
Cleaning Up with Regular Expressions
I don't have the time to do the whole thing but this will give you a start. I cleaned everything in one cell with this.
var sht = SpreadsheetApp.getActiveSheet();
var text = sht.getActiveCell().getValue();
var cleantext = text.replace(/[^\s\w]/g,'');//replace everything that's not whitespace or word characters with null
sht.getActiveCell().setValue(cleantext);
I used the line you provided as test data. Admittedly it needs a little tweaking because it's getting rid of some punctuation.
This is a little better.
function test()
{
var sht = SpreadsheetApp.getActiveSheet();
var text = sht.getActiveCell().getValue();
var cleantext = text.replace(/[^\s\w"!,]/g,'');//added "!,
sht.getActiveCell().setValue(cleantext);
}
So as you run it you may want to add a few more characters to don't replace list. That's it.
I have an expense report that I use to collect my expenses in different categories and I like to produce pie charts to help me get a big picture view of where my money is going. I use this Array Formula to help me gather the information into useful categories for me.
=ArrayFormula(IF(Row(C:C)=1,"Title",IF(LEN(C:C),IF(REGEXMATCH(C:C,"(?i)(string1|string2|string3|string4)"),D:D,""),)))
The regular expression provides an or function for adding additional matching for unexpected item appearing on my expense lists that I want to gather into these categories. If you need another matching term you just go into that formula and add another term as shown below
(string1|string2|string3|string4||string5)
The strings are replaced with real terms with no quotes unless they have quotes around them in the search target.
Here is some code that goes through one column of data and removes emojis from each cell.
You must replace Your Sheet Tab Name with the sheet tab name that the code should work on. This code currently only processes one column of data. The entire column of values is written back to the sheet in one write operation. Any character codes that are 5 characters or more are assumed to be emojis.
Test it on a few rows of data first.
function killEmojies() {
var arrayThisRow,columnOfValues,columnToRemoveEmojiesFrom,firstTwoChar,
i,innerArray,j,L,newCellContent,outerArray,
ss,sh,
targetSheet,thisCell,thisCellChar,thisCellVal,thisCharCode,thisCharCodeLength;
columnToRemoveEmojiesFrom = 1;
outerArray = [];
ss = SpreadsheetApp.getActiveSpreadsheet()
sh = ss.getSheetByName("Your Sheet Tab Name Here");
targetSheet = ss.getSheetByName("Your Sheet Tab Name Here");
columnOfValues = sh.getRange(1, columnToRemoveEmojiesFrom,sh.getLastRow(),1).getValues();
L = columnOfValues.length;
Logger.log('L: ' + L);
for (i=0;i<L;i++) {
thisCell = columnOfValues[i];//Get inner array
thisCellVal = thisCell[0];//Get first element of inner array
Logger.log(thisCellVal)
Logger.log('typeof thisCellVal: ' + typeof thisCellVal)
newCellContent = "";//Reset for every cell
innerArray = [];//Reset for every row loop
if (typeof thisCellVal !== 'string') {//This spreadsheet cell contains something
//other than text
innerArray.push(thisCellVal);
} else {
for (j=0;j<thisCellVal.length;j++) {//Loop through every character in the cell
thisCellChar = thisCellVal[j];
thisCharCode = thisCellChar.charCodeAt(0);//Character code of this character
thisCharCodeLength = thisCharCode.toString().length;
Logger.log('typeof thisCharCodeLength: ' + typeof thisCharCodeLength);
Logger.log('this val: ' + thisCharCode);
Logger.log('thisCharCodeLength: ' + thisCharCodeLength);
Logger.log(thisCharCodeLength < 5);
if (thisCharCodeLength === 5) {
firstTwoChar = thisCharCode.toString().slice(0,2);
Logger.log('firstTwoChar: ' + firstTwoChar)
}
if (thisCharCodeLength > 4 && (firstTwoChar === "54" || firstTwoChar === "55" || firstTwoChar === "56")) {
continue;//exclude character codes that are 5 or more characters long
//and start with 54 or 55
}
newCellContent = newCellContent + thisCellChar;
}
innerArray.push(newCellContent);
}
outerArray.push(innerArray);
}
targetSheet.getRange(1, columnToRemoveEmojiesFrom,outerArray.length,1).setValues(outerArray);
}
Replace emojis from text
I've found, you may use a REGEXREPLACE for that.
To replace all emojis from [A1] please try:
=REGEXREPLACE($A$1,"[๐Ÿป๐Ÿผ๐Ÿฝ๐Ÿพ๐Ÿฟยฉยฎโ€ผโ‰โ„ขโ„นโ†”-โ†™โ†ฉ-โ†ชโŒš-โŒ›โŒจโโฉ-โณโธ-โบโ“‚โ–ช-โ–ซโ–ถโ—€โ—ป-โ—พโ˜€-โ˜„โ˜Žโ˜‘โ˜”-โ˜•โ˜˜โ˜โ˜ โ˜ข-โ˜ฃโ˜ฆโ˜ชโ˜ฎ-โ˜ฏโ˜ธ-โ˜บโ™€โ™‚โ™ˆ-โ™“โ™Ÿ-โ™ โ™ฃโ™ฅ-โ™ฆโ™จโ™ปโ™พ-โ™ฟโš’-โš—โš™โš›-โšœโš -โšกโšงโšช-โšซโšฐ-โšฑโšฝ-โšพโ›„-โ›…โ›ˆโ›Ž-โ›โ›‘โ›“-โ›”โ›ฉ-โ›ชโ›ฐ-โ›ตโ›ท-โ›บโ›ฝโœ‚โœ…โœˆ-โœโœโœ’โœ”โœ–โœโœกโœจโœณ-โœดโ„โ‡โŒโŽโ“-โ•โ—โฃ-โคโž•-โž—โžกโžฐโžฟโคด-โคตโฌ…-โฌ‡โฌ›-โฌœโญโญ•ใ€ฐใ€ฝใŠ—ใŠ™๐Ÿ€„๐Ÿƒ๐Ÿ…ฐ-๐Ÿ…ฑ๐Ÿ…พ-๐Ÿ…ฟ๐Ÿ†Ž๐Ÿ†‘-๐Ÿ†š๐Ÿˆ-๐Ÿˆ‚๐Ÿˆš๐Ÿˆฏ๐Ÿˆฒ-๐Ÿˆบ๐Ÿ‰-๐Ÿ‰‘๐ŸŒ€-๐ŸŒก๐ŸŒค-๐ŸŽ“๐ŸŽ–-๐ŸŽ—๐ŸŽ™-๐ŸŽ›๐ŸŽž-๐Ÿฐ๐Ÿณ-๐Ÿต๐Ÿท-๐Ÿบ๐Ÿ€-๐Ÿ“ฝ๐Ÿ“ฟ-๐Ÿ”ฝ๐Ÿ•‰-๐Ÿ•Ž๐Ÿ•-๐Ÿ•ง๐Ÿ•ฏ-๐Ÿ•ฐ๐Ÿ•ณ-๐Ÿ•บ๐Ÿ–‡๐Ÿ–Š-๐Ÿ–๐Ÿ–๐Ÿ–•-๐Ÿ––๐Ÿ–ค-๐Ÿ–ฅ๐Ÿ–จ๐Ÿ–ฑ-๐Ÿ–ฒ๐Ÿ–ผ๐Ÿ—‚-๐Ÿ—„๐Ÿ—‘-๐Ÿ—“๐Ÿ—œ-๐Ÿ—ž๐Ÿ—ก๐Ÿ—ฃ๐Ÿ—จ๐Ÿ—ฏ๐Ÿ—ณ๐Ÿ—บ-๐Ÿ™๐Ÿš€-๐Ÿ›…๐Ÿ›‹-๐Ÿ›’๐Ÿ›•-๐Ÿ›—๐Ÿ›-๐Ÿ›ฅ๐Ÿ›ฉ๐Ÿ›ซ-๐Ÿ›ฌ๐Ÿ›ฐ๐Ÿ›ณ-๐Ÿ›ผ๐ŸŸ -๐ŸŸซ๐ŸŸฐ๐ŸคŒ-๐Ÿคบ๐Ÿคผ-๐Ÿฅ…๐Ÿฅ‡-๐Ÿงฟ๐Ÿฉฐ-๐Ÿฉด๐Ÿฉธ-๐Ÿฉผ๐Ÿช€-๐Ÿช†๐Ÿช-๐Ÿชฌ๐Ÿชฐ-๐Ÿชบ๐Ÿซ€-๐Ÿซ…๐Ÿซ-๐Ÿซ™๐Ÿซ -๐Ÿซง๐Ÿซฐ-๐Ÿซถ๐Ÿ‡ฆ-๐Ÿ‡ฟ#๏ธโƒฃ*๏ธโƒฃ0๏ธโƒฃ1๏ธโƒฃ2๏ธโƒฃ3๏ธโƒฃ4๏ธโƒฃ5๏ธโƒฃ6๏ธโƒฃ7๏ธโƒฃ8๏ธโƒฃ9๏ธโƒฃ]","")
I believe this regex will find all current emojis from your text.
Notes:
some emojis are compound for instance, an astronaut is ๐Ÿง‘๐Ÿผโ€๐Ÿš€. Regex needs to find only solid chars, so all compound emojis will be included.
I've tried to shorten the solution, and used actual emojis in RegEx. You may also see more "computer-like" solutions: [\u1F60-\u1F64]|[\u2702-\u27B0].... Those solutions use codes of emojis instead.
Another interesting option is given here. Remove all not printable chars: =REGEXREPLACE(A1,"[[:print:]]","")
skins are included:
please see my study here: Emojis-Lab.gsheet
Assuming all your text strings are single words followed by a space and then an Emoji, you can use the formula
=LEFT(A1,(FIND(" ",A1,1)-1))
This will return the textual contents of a cell only (A1 in this example).
If all your data is in a single column, you can just pull down and this will apply to all your data.

Concatenation in Column X of a Google Sheet, based in Column Y

I have a Google Sheet with addresses(talking about real life, street addresses) on one column, and status on those addresses (like VACANT, EVICTION, OCCUPIED) on another. I'm trying to create a formula that will allow me to make a new column with a concatenation of the address + a specific tag based on the status. For example, if I have address "11423 Whisper Sound Drive, FL", with the status "OCCUPIED", I wanna have another column that says "11423 Whisper Sound Drive, FL < green-dot >"
My current approach isn't working, I'm getting a parse error:
= function letsDoThis() {
var addressValue = getCell(D2);
var statusValue = getCell(G2);
if (statusValue == "OCCUPIED")
{
var newValue = addressValue + " <green-dot>";
getCell(O2).setValue(newValue);
}
}
You can try the following formula based solution:
Try the following formula in cell O2:
=if(G2="OCCUPIED";D2&" <green-dot>";)

Writing a string of multiple date / time to a single cell

I have an array of a couple (the array is up to 10) date/time that I want to write to a spreadsheet using getRange().setValues(). I'm converting the array to a string and it looks correct in Logger.
[Mon Feb 02 14:01:00 GMT-06:00 2015, Tue Feb 02 01:00:00 GMT-06:00 2016, , , , , , , , ]
When I try to write the string to a single cell in a sheet:
target6.setValues(source_range6_values);
I get this error:
Incorrect range width, was 10 but should be 1 (line 84, file "Code")
Edited 4/28/2014 adding entire script:
/**
* Copies source range and pastes at first empty row on target sheet
*/
function CopyIt(){
//Establishing source and target sheets
var source_spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var target_spreadsheet = SpreadsheetApp.openById("0AhCv9Xu_eRnSdHpLTkc0d1ZURUtyTU9oRjdFbmpMUFE");
// Get source and target sheets - can be the same or different
var sourcesheet = source_spreadsheet.getSheetByName("Form Responses");
var targetsheet = target_spreadsheet.getSheetByName("Work_Orders");
//Get row of last form submission
var source_last_row = sourcesheet.getLastRow();
// Check for answer to Do you need a Flyer Created? If No, end now. If Yes, continue.
var check = sourcesheet.getRange("T"+(source_last_row)).getValue();
if (check == 'Yes') {
//Pulling date(s) from the users form entry (source sheet) into an array
var daterange = sourcesheet.getRange("H"+source_last_row+":Q"+source_last_row);
//Getting the values of the array
var classDate = daterange.getValues();
//changing the array values to a string
classDate.toString();
//Building a new variable with the string to be inserted below in the target sheet
var source_range6_values = classDate;
//source_range6_values.toString();
Logger.log(classDate[0]);
// Get the last row on the target sheet
var last_row = targetsheet.getLastRow();
//Setting the target cell in the Marketing Work Order sheet
var target6 = targetsheet.getRange("U"+(last_row+1));
// Aadding a new row in the target sheet
targetsheet.insertRowAfter(last_row);
//Inserting the values of source_range6_values into the target sheet. Unfortunately it does not enter the data into the same field and it's in military time.
target6.setValue(source_range6_values);
Logger.log(source_range6_values);
}
}
To give a correct answer for your question, i guess i need to know how you get the value of source_range6_values.
One quick guess is you might want to use target6.setValue instead of target6.setValues since you want to write the data into one cell only...
A quick & dirty way would be to replace the commas(with spaces):
source = String(source_range6_values).replace("," , " ");
I've had fun with GAS and variables. Casting it as a String should let you use the string functions on it. If that doesn't work can you share a mock-up of your sheets so I can take a look?
edit:
I had to play around with it a bit, seems google's version of .replace() only replaces the first instance (and doesn't allow .replaceAll() ).
I edited your code starting on line 23:
//Getting the values of the array
var classDate = daterange.getValues().toString();
//Building a new variable with the string to be inserted below in the target sheet
//Google has bugs, .replace() seems to only replace the first instance
//-while {} loop replaces all of them
while (!classDate.equals(classDate.replace("," , " "))) { classDate = classDate.replace("," , " "); };
var source_range6_values = classDate;
All the dates are in one cell if you change only those lines (and no errors).
I appreciate the help you two have given me trying to answer this question. #swimmingwood fixed the actual capture of the data into a string, but it left commas and when I inserted it into the target sheet, it wrote it to multiple cells with an error. It did write to the sheet but the error had you use a CTRL-E (inside the taget sheet) to complete the insert and wrote them into separate cells.
#MickATX suggested the code to replace the commas in the string with a space, which would be fine, but apparently he discovered a Google scripting problem that would only allow for the first comma to be replaced and ignore the rest. Great knowledge never-the-less.
I ended up using a formula in an addition cell in the source sheet that looked like this:
=ArrayFormula(CONCATENATE(REPT(TEXT(H2:Q2,"mm/dd/yyyy hh:mm a")&CHAR(10),H2:Q2>0)))
This formula wrote all the date/time entries provided by the form entry into one cell of the source sheet and ONLY the number of entries (1-10). I then wrote that single cell to the target sheet via the script.
Thanks to #swimmingwood and #MickATX for trying to help me, both provided worthy knowledge.
I've read a couple of strange answers here...
If you write an 2D array to a sheet it will obviously be written accross multiple cells... commas are definitely not the issue but the nature of the object is.
Simply convert your array into a string using .toString() or .join() (the latter providing the advantage you can choose the separator to use) and setValue() (without S) at the place you want.
the commas you see in the logger are only typographic representation of array elements separators...
And, last point : the .join() or .toString() methods return new variables, they don't modify the original value so when you write classDate.toString(); you are not doing anything ...
you should write it like this :
classDateAsAString = classDate.toString();
finally your code :
function CopyIt(){
//Establishing source and target sheets
var source_spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var target_spreadsheet = SpreadsheetApp.openById("0AhCv9Xu_eRnSdHpLTkc0d1ZURUtyTU9oRjdFbmpMUFE");
// Get source and target sheets - can be the same or different
var sourcesheet = source_spreadsheet.getSheetByName("Form Responses");
var targetsheet = target_spreadsheet.getSheetByName("Work_Orders");
//Get row of last form submission
var source_last_row = sourcesheet.getLastRow();
// Check for answer to Do you need a Flyer Created? If No, end now. If Yes, continue.
var check = sourcesheet.getRange("T"+(source_last_row)).getValue();
if (check == 'Yes') {
//Pulling date(s) from the users form entry (source sheet) into an array
var daterange = sourcesheet.getRange("H"+source_last_row+":Q"+source_last_row);
//Getting the values of the array
var classDate = daterange.getValues();
var source_range6_values = classDate.join(' & ');// using & as separator for example
// Get the last row on the target sheet
var last_row = targetsheet.getLastRow();
//Setting the target cell in the Marketing Work Order sheet
var target6 = targetsheet.getRange("U"+(last_row+1));
// Adding a new row in the target sheet
targetsheet.insertRowAfter(last_row);
//Inserting the values of source_range6_values into the target sheet. Unfortunately it does not enter the data into the same field and it's in military time.
target6.setValue(source_range6_values);
Logger.log(source_range6_values);
}
}
Now if you want to format the dates in a more civilized way, that should be handled a bit differently... let me know if you still need it / want it.