writing delimited text as a string to a spreadsheet - google-apps-script

i have a short script where i'm trying to grab data from a URL and write it to a sheet of an existing spreadsheet. the script is as follows:
function urlDataImport() {
var input = "https://reports.acc-q-data.com/clientreports/ecaldwell_201206192722/ecaldwell_20122722.txt";
// The code below gets the HTML code.
var response = UrlFetchApp.fetch(input);
var data = response.getContentText();
Logger.log(data);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ptSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("pt");
ptSheet.getActiveRange().setValues(data);
}
the information in data is tab delimited and shows up properly in the log but because it's a string i can't use .setValues to write it to the sheet pt and i'm not sure how to get the information from the URL in any other way.
i'm sorry for the rudimentary nature of this question but i'm very new to scripting so any help would be appreciated.
Updated Code:
function ptDataImport() {
var input = "https://reports.acc-q-data.com/clientreports/ecaldwell_201206192722/ecaldwell_2012062.txt";
var response = UrlFetchApp.fetch(input); // Get the data from the URL as an object.
var data = response.getContentText(); // Convet the object to text
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("pt"); // Get the sheet to write the data to
var rows = data.split('\n'); // Splits the text into rows
dataSheet.clear();
var dataSet = new Array();
for ( var i in rows){
dataSet[i] = rows[i].split('\t'); // Split the rows into individual fields and add them to the 2d array
}
dataSet.pop(); // Had a blank row at the bottom that was giving me an error when trying to set the range - need to make this conditional somehow
var numColumns = dataSet[0].length;
var numRows = dataSet.length;
var lastRow = dataSet[(numRows -1)];
dataSheet.getRange(1,1,numRows,numColumns).setValues(dataSet); // Get a range the size of the data and set the values
}

#Serge, I think Evan's question was different. Evan is concerned that the split does not take rows into consideration.
The solution to that is to use two splits. First,
var rows = data.split('\n');
And then
for ( var i in rows){
tmp = rows[i].split('\t'); // Use Serge's method if this doesn't work
/* Get the range here */
range.setValues([tmp]);
}

Range.setValues() takes a 2-D array as input.
I'm not sure what you want to do. If all you want to do is write data into a cell, then use this piece of code
ptSheet.getActiveRange().setValues([[data]]);
If you want to write each of the elements in data to a row in a spreadsheet, then you can use
var tmp = data.split(DELIMITER);
/* Get the correct range here */
range.setValues([tmp]);
Notice how you are creating a 2-D array in the first case and in the second case.

I guess the easiest thing to do is to convert those tabs in something else, commas for example, that's after all where the 'c' of csv comes from... you can then write it wherever you want.
Exemple :
commaString = tabString.replace(\t/g,',') ; should work but I'm not an expert in regEx... if I'm wrong someone will for sure correct it ;-)

Related

I am trying to filter data from 1 spreadsheet into two separate spreadsheets through Apps Script using an for loop and if function

I am fairly new to appscript and only did a little coding in college. Here is my issue:
I am trying to filter data from one sheet into two separate existing sheets. The existing sheets already have data and formulas in it. Also, the filtered data needs to update onEdit and filtered the data into the first row that does not contain text. Another caveat is that I still need to be able to manually enter data into the cells as well from time to time and I need the function to realize this and not overwrite the manually entered data.
We are using QR codes to import data for inventory and the imported data needs to be filtered. But, we need to be able to manually input new line items into these sheets still for inventory that is non related to existing QR codes.
The function will run and filter the data correctly for the most part, but the row spacing is all over the place and the first cell, typically throws a #REF error and then continues on with the function.
At this point, I'm pretty stuck.
(I know that it will need to become an onEdit(e) function later, but just need the code to work first)
Here is my function:
function myfunction(){
var ss = SpreadsheetApp;
var orderlog = ss.getActiveSpreadsheet().getSheetByName("Order Log - COMM");
var scanit = ss.getActiveSpreadsheet().getSheetByName("Scan-It Data");
var mfg = ss.getActiveSpreadsheet().getSheetByName("Order Log - MFG");
var scanlastRow = scanit.getLastRow();
var commlastrow = orderlog.getLastRow();
// For loop to filter Vendor
for(var i=1;i <= scanlastRow;i++){
// Grab the Value from the Scan-It Data Sheet
var workingcell = scanit.getRange(1 + i, 2 );
var val = workingcell.getValue();
// If the Value equals IMMCO, send it to the MFG Sheet
// If the Value is anything else, send it to the COMM Sheet
if (val == "IMMCO") {
// Grab the Scan-It Data and send it to the MFG sheet
var scanitrange = scanit.getRange(1 + i, 1 );
//var mfglastrow = mfg.getLastRow();
//mfg.insertRowAfter(mfglastrow);
var mfgrow = mfg.getRange(71 + i, 1 );
scanitrange.copyTo(mfgrow);
} else {
//Grab the Scan-It Data and send it to the last row of the COMM Sheet
var scanitrange = scanit.getRange(1 + i, 1);
var orderlogrow = orderlog.getRange(328 + i, 1 );
//orderlog.insertRowAfter(commlastrow);
//var commrange = orderlog.getRange("A327:A"+(commlastrow+1));
scanitrange.copyTo(orderlogrow);
}
}
}
I would recommend that you use a tried and tested solution such as the moveRowsFromSpreadsheetToSpreadsheet_ script. The code is almost 800 lines long so it is impractical to quote here, but it is quite simple to configure using the parameters section.

How to write to a cell when given a range with the onFormSubmit trigger? (Google apps script)

I am new to coding with google apps script and am trying to make a simple case checker for my spreadsheet.
In this case, I want to check if the first letter of a name is capitalized, and if it isn't, I want to replace it with a corrected version (same name, just with the first letter capitalized.)
This code returns an error when trying to run it in the editor (cannot read property "range" of undefined.) I presume this is because it is using an onFormSubmit trigger, so the only way to test it would be to actually submit a form response.
When a new form response IS posted and the function is triggered, it doesn't seem to do anything on the spreadsheet's end. The new cells that contain the first name and last name (or any of the new cells for that matter) simply don't change, first-letter-capitalized or not.
When using a separate function that refers to the cells the same way (taking a range of the newly submitted cells and designating them row[numberhere] within the for loop) it reads their strings just fine.
function caseCheck(r) {
var range = r.range;
var data1 = range.getValue();
for (var r in data1) {
var row1 = data1[r];
var firstName = row1[2].getValue;
var lastName = row1[3].getValue;
var firstNameC = firstName[0].toUpperCase();
var lastNameC = lastName[0].toUpperCase();
if (firstName[0] != firstNameC) {
var firstNameL = firstName.length();
var firstNameSS = firstName.substring(1,firstNameL);
var firstNameCorrected = firstNameC + firstNameSS;
row1[2].setValue(firstNameCorrected);
}
if (lastName[0] != lastNameC) {
var lastNameL = lastName.length();
var lastNameSS = lastName.substring(1,lastNameL);
var lastNameCorrected = lastNameC + lastNameSS;
row1[3].setValue(lastNameCorrected);
}
}
}
You have several issues with the code as shown.
I think you meant to use the plural range.getValues() not range.getValue() as .getValue just returns the Object inside the top left cell of the range. If data1 is a string, then for (var r in data1) is just looping over a string, not an array of values.
Assuming that you fix data1 so it is an array of arrays, then row1 is just a JavaScript array, presumably an array of strings, so the various places where you are using e.g. row1[2].getValue (which don't have parentheses anyways) and row1[2].setValue(firstNameCorrected) shouldn't have any effect because these are strings, not Range objects.
What you need to do is mutate the data array as needed, and then call range.setValues(data) with the mutated data.
function caseCheck(r) {
var range = r.range;
var data = range.getValues();
for (var r in data) {
var row = data[r];
// do whatever mutation to row you want
}
range.setValues(data);
}
As a side-note, personal preference/suggestion, this kind of imperative mutating code is very hard to read and maintain. Look into using more (and smaller) functions...
function caseCheck(r) {
var range = r.range;
var data = range.getValues();
var newData = data.map(rowCapitalizeFunction);
range.setValues(newData);
}
function rowCapitalizeFunction(row) {
var firstName = row[2];
// etc ... do what you need to do
return [/* send back a new array with new values, much easier to understand! */];
}

Random string generator randomizing too often

I'm looking for input on a small random string generator project.
I'm trying to create a random string generator that puts three words together, where I can then save strings that I like to another sheet.
I'm using a basic script to assign a RANDBETWEEN formula to 3 specific cells, which works great to generate the strings, but it keeps recalculating with each additional step in the script it seems. I'd like to run one function then if I like the string I would run another function to store the string. However, when I try that it has already recalculated the RANDBETWEEN formulas and it saves something completely different.
I have an example sheet here:
https://docs.google.com/spreadsheets/d/1TWziyjjLQJJApkHCqrLzNGMFU0sf-vNEOOSatuhHURo/edit?usp=sharing
And here is the code I'm using for the "Go" and "Save" buttons, respectively:
function generateString() {
var ss = SpreadsheetApp.openById('1b9rP39sgZDOZqu7AmZhOxX9J8CMukmUw7NPY3Qzuq78');
var sheet = ss.getSheetByName('Randomizer');
var cell = sheet.getRange('D4');
var cell2 = sheet.getRange('E4');
var cell3 = sheet.getRange('F4');
cell.setValue('=INDEX(A:A,RANDBETWEEN(1,counta(A:A)))');
cell2.setValue('=INDEX(A:A,RANDBETWEEN(1,counta(A:A)))');
cell3.setValue('=INDEX(A:A,RANDBETWEEN(1,counta(A:A)))');
var cell4 = sheet.getRange('P4');
cell4.copyTo (sheet.getRange ('P5'), {contentsOnly: true}); //an attempt to paste values to record the random string
}
function saveString() {
var ss = SpreadsheetApp.openById('1b9rP39sgZDOZqu7AmZhOxX9J8CMukmUw7NPY3Qzuq78');
var sheet = ss.getSheetByName('Randomizer'); //replace with source Sheet tab name
var range = sheet.getRange('P4'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('1b9rP39sgZDOZqu7AmZhOxX9J8CMukmUw7NPY3Qzuq78');
var tsheet = tss.getSheetByName('Saved Strings'); //replace with destination Sheet tab name
tsheet.getRange(tsheet.getLastRow()+1, 1, 1, 1).setValues(data);
}
Please let me know if anyone has some ideas on how to make this work properly. Thanks!
RANDBETWEEN the same as RAND are volatile functions. That means that their results changes every time that spreadsheet is recalculated.
If you need to keep the randomized to result be "freezed" for a while instead of this functions one alternative to consider is the use of a custom function as they are recalculated only when at least one of its arguments changes.
Related
Refresh data retrieved by a custom function in Google Sheet

Lookup cell reference of given value

I have a spreadsheet with hundreds of rows and Column A is a unique record number.
I would like to learn to be able to find cell reference based on the inputted unique record number.
For example if in Call A1, I enter value 11, ho can I retrieve cell row (eg: 17) using google script.
Thank you for help
Taizoon
You can build a simple and small Ui that does a "search" in your first column and activates the found cell (and the whole row). An example is shown below, You have an option to use it repeatedly (like it is now) or just once by changing one line of code, see comment at the end of the handler function. :
function showInSheet() {
var app = UiApp.createApplication().setTitle('Search and Select').setWidth(250).setHeight(60);
var panel = app.createVerticalPanel();
var searchHandler = app.createServerHandler('searchRow').addCallbackElement(panel);
var Hpanel = app.createHorizontalPanel();
var search = app.createTextBox().setName('search').setId('search').setWidth('70').addKeyUpHandler(searchHandler);
var warning = app.createHTML('incomplete or invalid entry').setId('warning').setStyleAttributes({'padding-left':'10px','background':'yellow','fontSize':'8pt'}).setVisible(false);
app.add(panel.add(Hpanel.add(search).add(warning)));
SpreadsheetApp.getActive().show(app);
}
function searchRow(e){
var app = UiApp.getActiveApplication();
var item = e.parameter.search;
var sh = SpreadsheetApp.getActiveSheet();
var data = sh.getRange(1,1,sh.getLastRow(),1).getValues().join().split(',');// the 2D array is "flattened" and splitted to get a 1D array
Logger.log(data.length);
var idx = data.indexOf(item);// in a "simple" array we can use this array function more easily to seach in it ;-)
Logger.log(idx);
if(idx>data.length || idx==-1){app.getElementById('warning').setVisible(true) ; return app};
idx++;// increment because rows count from 1 instead of 0 in arrays
var itemRange = sh.getRange(idx,1,1,sh.getMaxColumns());
sh.setActiveSelection(itemRange);
// return app.close();// can be replace by next line (uncommented)
app.getElementById('search').setText('');app.getElementById('warning').setVisible(false);return app;
}

parse data fetch from html

I'm trying to get some data from the federal reserve and paste into my spreadsheet.
So here is my code
function myFunction() {
var response = UrlFetchApp.fetch("http://research.stlouisfed.org/fred2/data/TWEXMANL.txt");
a=response.getContentText();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var InputSheet = ss.getSheetByName("Sheet5");
InputSheet.getRange("E5:E5").setValue(a);
}
This code pastes all of the output into E5. I just want the data following the "Date" and "Value" pasted into 2 columns.
Can anybody help me with this? I'm sure it's pretty simple for you guys.
Thanks.
Using a little string manipulation, this becomes very easy:
function myFunction() {
var response = UrlFetchApp.fetch("http://research.stlouisfed.org/fred2/data/TWEXMANL.txt");
a=response.getContentText();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var InputSheet = ss.getSheetByName("Sheet1");
//Slice off the text above the columns
var allData = a.slice(a.indexOf("DATE VALUE"));
//Trim spaces between date and value to just 1 space for splitting
allData = allData.replace(/ +/g, " ");
//Split the text so each line is a row
var splitData = allData.split("\n");
//For some reason, there is an extra line, so remove it
splitData.pop();
//Split each row so data is one column and value is another
for(var i = 0; i < splitData.length; i += 1) {
splitData[i] = splitData[i].split(" ");
}
//Save to spreadsheet. +4 because you start at E5. Note the change to F on the right.
InputSheet.getRange("E5:F" + (splitData.length + 4)).setValues(splitData);
}
I start by taking off the little intro text. I then split the string into an array containing the rows of data. I split each row (a string) into an array as well. This gives me a array I can use setValues() on at the bottom. Because this isn't just one cell, I have to specific the exact width and height or it fails.
If you'd like to see the data at any point in there, I recommend Logger.log(splitData);