Google Sheets Split Text to Column by First Text character - google-apps-script

I have 1 column of data that I want to split to units & product name.
In the desired format its not really necessary for headers, so if we need to omit them that's fine. I normally have around 200+ rows of data that I want to split.
Currently I do it by, pasting column to excel & splitting via fixed column width. It does the work as I desire and also without any spaces before the new columns. But I want to be able to do this in sheets itself if possible.
I found this great apps script in stackoverflow that works great for my needs. But only problem is that it somehow seems to put extra spaces on some of the data rows.
So is it possible to set the 2nd substring to start from the first letter instead of counted characters.
split text to column script
for (var i=startrow-1;i<LR;i++){
var outputrow=[];
var unit = values[i][0].substring(0,1);
var name = values[i][0].substring(**SET TO FIRST TEXT CHARACTER**);
My sample sheet: https://docs.google.com/spreadsheets/d/1uO6mw6T9vK9mN8ZRtCJXX5UT8yV_rL-4_fD2TZbiDbk/edit?usp=sharing

In D2 I entered
=ArrayFormula(if(len(DATA!A2:A), trim(regexextract(DATA!A2:A, "^(\d+)\s(.*)$")),))
If you want to have the first column formatted as number you can try
=ArrayFormula(if(len(DATA!A2:A), {regexextract(DATA!A2:A, "^(\d+)\s")+0, trim(regexextract(DATA!A2:A, "\s(.*)$"))},))
Or with script try something like
function myFunction() {
const ss = SpreadsheetApp.getActive()
const values = ss.getRange('DATA!A2:A').getValues().filter(String).flat().map( c => {
const splitted = c.split(" ");
const num = splitted.shift();
return [Number(num), splitted.join(" ").trim()]
})
ss.getSheetByName('Result').getRange(2, 1, values.length, 2).setValues(values);
}

Related

Data into rows and colums

I'm relatively new to this, I've written a function in Google Apps Script, getting data from an API.
The problem is that it's inserted into one single cell, instead of multiple rows and columns.
Can anybody help?
Tried googling examples
What I do
function spotpriser() {
var priser = 'api.energidataservice.dk/dataset/Elspotprices' + '?start=2022-07-01&end=2022-07-02' + '&sort=HourDK';
var response = UrlFetchApp.fetch(priser);
Logger.log(response);
var fact = response.getContentText();
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1,1).setValue([fact]);
}
if you do getRange(1,1).setValue() it is normal that all the data get inserted into one cell only: the one define by the range (aka A1).
Instead what you probably want to do is to get a larger range, corresponding the dimensions of your retrieved data.
For example, let's say you retrieved 3 lines of data, and one line of data is supposed to be displayed on 2 columns.
You first need to create an array of size 5 (nb of rows) where each element will also be an array, of size 2 (nb of cols for each element).
let myArray = [
[elt1_col1_value, elt1_col2_value],
[elt2_col1_value, elt2_col2_value],
[elt3_col1_value, elt3_col2_value]
]
Then you can insert this array into the right number of cells, i.e defining the right range
sheet.getRange(1,1,myArray.length,myArray[0].length).setValues(myArray); // start at row 1, col 1, insert the right number of rows and cols based on the array
Note that I use setValues (with the s) to indicate that it writes in several cells.
Also make sure there is at least one element in myArray otherwise myArray[0].length will throw an error.
Documentation for getRange.

Trying to append rows what am I not grasping?

Summary:
I need to get a range of values from one sheet, then set them into the first empty row of the second sheet. If that row is full, then append to the next.
I can get the script to set values into their corresponding cells, but not append; and I've been able to append a single cell value into an empty cell, but not the entire range. What am I not comprehending?
The goal:
Basically I'm taking user input (lets say race data) and saving it to another sheet for referencing later. (possibly to average race times by weight and height or something)
Research: I'm a bit new to this, but I've also done a good bit of research, such as ben collins free introductory course and other questions from here (just to name a couple):
[Get Range] SpreadsheetApp: getRange and setValues
[Copy Range] How to copy row ranges in Google docs?
Code
Grab my data:
const data1 = sheet1.getRange("A2:F2").getValues(); //grab data
Sets the range where I want it, but doesn't append:
sheet2.getRange("A2:F2").setValues(data1) //gets range and sets the value
So I've tried:
function r () {sheet2.getRange(newRow,1,1,data1.length).setValues(data1)};
return (r);
and even added:
sheet2.appendRow(data1);
(newRow is essentially getLastRow)
The above gives me a row of set values, then appends this in the following row: [Ljava.lang.Object;#f2a6014
-which in my research I've found what it is, but I don't understand why it happens.
I know I'm overlooking something or arranging something incorrectly but I cant figure out what it is that I'm not understanding.
Using your first two example I wrote this script and it works:
function copydata() {
const ss=SpreadsheetApp.getActive();
const sheet1=ss.getSheetByName('Sheet1');
const sheet2=ss.getSheetByName('Sheet2');
const data1 = sheet1.getRange("A2:F2").getValues();
sheet2.getRange("A2:F2").setValues(data1);
}
And this works also assuming that you realize that data1 is only a single row but it's still a two dimensional array so you have to use data1[0] to extract the single dimensional array from the two dimensional array
function copydatatofrom() {
const ss=SpreadsheetApp.getActive();
const sheet1=ss.getSheetByName('Sheet1');
const sheet2=ss.getSheetByName('Sheet2');
const data1 = sheet1.getRange("A2:F2").getValues();
sheet2.getRange("A2:F2").setValues(data1);
sheet2.appendRow(data1[0]);
}

Trying to copy a variable-length list

I'm trying to copy a list from Sheet A to sheet B. (I have the number of rows used by the data in the list saved in a cell, if needed.)
The spreadsheet file contains 5 sheets, of which "Analysis" is one. It contains 4-5 tables, each separated by a blank row.
The list itself is variable in length - sometimes it's 9 rows, sometimes its 17. Thankfully, it's always 5 columns wide.
Once I get the list into Sheet B, I need to set all cell borders to TRUE.
Here's the code that I've been playing with:
var sss =
SpreadsheetApp.openById(Sheet A);
var ss = sss.getSheetByName('Analysis'); //
var tblRows = sss.getRange('Analysis!K190').getValue();
var range = SpreadsheetApp.getRange('190,5,tblRows,5'); //assign the range you want to copy
var data = range.getValues();
var tss =
SpreadsheetApp.openById(Sheet B);
var ts = tss.getSheetByName('2018');
ts.getRange(ts.getLastRow()+1,1,tblrows,5).setValues(data);
(I'm not sure that this formatted properly)
Anyhow, I have the number of rows used by the list saved as a variable in a spreadsheet cell, and I'd like to use that, because I have found "getLastRow" to get the last row of the sheet, not the last row that is non-blank. (It might be giving me trouble because I'm doing something wrong, tho...) I know that I've messed up, so feel free to throw everything out and start over, if needed.
Anybody care to throw some ideas my way?

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.

setFormulas to a new spreadsheets when created

I have been searching through question and example everywhere but I can not seem to find an answer. I need to set these formulas in the header row and columns AQ:1 to AV:1(AQ1:AV1).
["={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}",
"={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}",
"={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}",
"={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}",
"={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}"],
and I need to put this into the second row of column AQ (AQ2).
["=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
I keep getting this error message and I cannot save the script.
Missing ] after element list. (line 138, file "Code")
I think I know why but I need the headers to be titled with the correct text because I use the headers in other functions.
function setFormulas(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This sets the formulas to be a row of sums, followed by a row of averages right below.
// The size of the two-dimensional array must match the size of the range.
var formulas = [
["={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}",
"={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}",
"={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}",
"={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}",
"={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}",
"={"Wages:";ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
["=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
];
var cell = sheet.getRange("AQ1:AW2");
cell.setFormulas(formulas);
}
Am I missing something or am I doing it completely wrong and need to find another way to do it. I also need to add the formulas to every sheet in the spreadsheet but I have not been able to test if it works. Thank you in advance for any help.
UPD:
It seems like double quotes are interfering here. To avoid this, you can use single quotes for formula enclosure and double quotes within formula, like this:
'={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}'
As mentioned in comments:
Arrays would expand so you are likely to need setting formulas in one row, like AQ1:AW1
Besides, if there's source data in columns AQ:AU (by the looks of formulas), setting array formulas in the same columns will most likely return error: Array result was not expanded because it would overwrite data in AQ18.
You seem to have an extra } at the end of the last formula
Try this and adjust to your needs:
function setFormulas(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This sets the formulas to be a row of sums, followed by a row of averages right below.
// The size of the two-dimensional array must match the size of the range.
var formulas = [
['={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}',
'={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}',
'={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}',
'={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}',
'={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}',
'={"Wages:";ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}',
'=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))']
];
var cell = sheet.getRange("AW1:BC1");
cell.setFormulas(formulas);
}