Formatting Issues with CSV import to Google Sheets from Gmail - csv

I'm currently importing CSV data from gmail emails automatically using the following script:
function importsearchresultsCSVFromGmail2() {
var threads = GmailApp.search("Scheduled report (********** **** *******)");
var messages = threads[0].getMessages();
var message = messages[messages.length - 1];
var attachment = message.getAttachments()[0];
// Is the attachment a CSV file
attachment.setContentType('text/csv');
//attachment.setContentTypeFromExtension();
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sh0 = sheet.getSheetByName("Sheet1")
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
// Remember to clear the content of the sheet before importing new data
sh0.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
GmailApp.markMessageRead(message);
}
}
However, some address fields in the csv are formatted in the entire cell of the csv to be:
Address Layout 1
and some will be shown as "123 New Road, London, NE3 1RD". < These display correctly in the import, however the formatted version above is spread across a number of cells and messes up the original layout of the csv.
Is there a way to ensure the imported cell (that contains the formatted address cell) wont spread across to other cells?
Current CSV File Example
Current Google Sheet Result
Thanks in advance.
Tom

Here is a variant (not so elegant as Yuri solution)
function importCSVFromGoogleDrive() {
var file = DriveApp.getFilesByName("CSV TEST.csv").next();
var csvString = file.getBlob().getDataAsString().replace(/\n/g, '♥').replace(/\r♥/g, '\r\n')
var csvData = Utilities.parseCsv(csvString);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('mySheet');
sheet.clear();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
SpreadsheetApp.flush()
let ranges = SpreadsheetApp.getActive()
.createTextFinder("♥")
.matchEntireCell(false)
.matchCase(true)
.matchFormulaText(false)
.ignoreDiacritics(true)
.findAll();
ranges.forEach(function (range) {
range.setValue(range.getValue().replace(/♥/g,"\n"));
});
}
adapted to your situation
var csvData = Utilities.parseCsv(attachment.getDataAsString().replace(/\n/g, '♥').replace(/\r♥/g, '\r\n'), ",");
sh0.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
SpreadsheetApp.flush()
let ranges = sh0
.createTextFinder("♥")
.matchEntireCell(false)
.matchCase(true)
.matchFormulaText(false)
.ignoreDiacritics(true)
.findAll();
ranges.forEach(function (range) {
range.setValue(range.getValue().replace(/♥/g, "\n"));
});

It would be better if you show your CSV as a text.
I think there are \r and \n inside a quote marks ". You can try to replace them with spaces if you change this line:
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
to this:
var s = attachment.getDataAsString().replace(/"[^"]+?"/, x => x.replace(/[\r\n]+/g, ' '));
var csvData = Utilities.parseCsv(s, ',');
Output:
Update
Here is the variant of about the same function. It does the same thing: replaces \r and \n within quote marks. But it replaces them with the special symbol. And replaces this symbol back to \n after the data is pasted on the sheet:
function get_csv() {
var threads = GmailApp.search("Scheduled report"); // subject
var message = threads[0].getMessages().pop(); // get last message from first thread
var attachment = message.getAttachments()[0]; // first attachment
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Sheet1");
// get the csv string and replace \n with the symbol ¶
var s = attachment.getDataAsString().replace(/"[^"]+?"/g, x => x.replace(/[\r\n]+/g, '¶'));
var csvData = Utilities.parseCsv(s, ',');
sh.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
sh.getDataRange().createTextFinder('¶').replaceAllWith('\n'); // restore \n inside cells
GmailApp.markMessageRead(message);
}
Result:
Here is the CSV data (not sure if the \r\n are intact after copy and paste):
Activity date & time,Status change,Postcode,Introducer,Marketing source,Assigned user,Lead reference,Lead date,Signed Date,Offered Date,Completed Date,Title,First name,Last name,Lead type,Lead group,Site,Product,"Security Address, if different from above"
01/02/2022,Signed,NE3 1RD,Me,,Me,172312026,15/11/2021,None,None,None,Mr.,John,Smith,Band A,Type 1,Leads.com,Fixed 5,"123 New Road, LONDON, NE3 1RD"
01/02/2022,Signed,NE3 1RD,Me,,Me,172312026,15/11/2021,None,None,None,Mr.,John,Smith,Band A,Type 1,Leads.com,Fixed 5,"123 New Road
LONDON
NE3 1RD"

Related

Apend CSV from gdrive

I am trying to append data from csv saved in google drive to another file in google sheets, I want to ensure that the data gets pasted without the headers. I keep getting an error.
function getCSVAndAppend(spreadsheetId, folderId, filename)
{var folder = DriveApp.getFolderById('1TMFXWDTJpwqTY0JsCefuAean4n9fWIIh');
var files = folder.getFilesByName('Dealers joined data.csv');
var openSpreadsheet = SpreadsheetApp.openById('1E5z7Qd3KRb5geNKlQiYhliYCOtJ0A8ICmZFcUcA1-lI');
var activeSheet = SpreadsheetApp.getActiveSheet();
if ( files.hasNext())\
{var file = files.next();
var csv = file.getBlob().getDataAsString();
var csvData = Utilities.parseCsv(csv);
var csvDataNoHeader = csvData.splice(1,csvData.length-1)
var lastrow = activeSheet.getLastRow();
activeSheet.getRange(lastrow + 1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}
It's possible that there are other issues as noted by Yuri. But this splice looks incorrect to me
var csvDataNoHeader = csvData.splice(1,csvData.length-1)
I think the 1 should be zero and the other parameter should be 1 but it might actually be easier just to use shift to remove the first row. I think csvData is a 2d array.

Exclude final row during csv file dump into google sheet

I am extracting a csv file from my Gmail and dumping it into a Google Sheet using this Google App Script.
But the csv file I am receiving has a 'total' towards the end of it, I would like to load all the data except last row from the csv file i.e., n-1
How do I tweak the below code to such that the code excludes last delimited value
function importfromGmail() {
var sheetName = "Stackoverflow"; // Please set the tab name you want to overwrite the data.
var threads = GmailApp.search("label:Stackoverflow"); // Please set here.
var messages = threads[0].getMessages();
var message = messages[messages.length - 1];
var attachment = message.getAttachments()[0];
var data = [];
Logger.log("ContentType: "+attachment.getContentType())
//Logger.log(Utilities.parseCsv(attachment.getDataAsString(), ","));
data = Utilities.parseCsv(attachment.getDataAsString(), ",");
Logger.log(data.length)
if (data.length > 0) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
Logger.log(SpreadsheetApp.getActiveSpreadsheet().getUrl());
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}
}
In your situation, how about modifying your script as follows?
From:
data = Utilities.parseCsv(attachment.getDataAsString(), ",");
To:
data = Utilities.parseCsv(attachment.getDataAsString(), ",");
data.pop();
By pop(), the last element is removed from data.
Reference:
pop()

Google sheets export to txt

Hello I made this script to export the data from a column to a .txt on my google drive
function createOrAppendFile() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var range = sheet.getRange('G3:G50');
var rows = range.getValues();
var fileName="test.txt";
var folderName="Videos";
var data = rows.splice(0);
var str = data.map(function(e) {return e.join()}).join("\n");
var content = str;
// get list of folders with matching name
var folderList = DriveApp.getFoldersByName(folderName);
if (folderList.hasNext()) {
// found matching folder
var folder = folderList.next();
// search for files with matching name
var fileList = folder.getFilesByName(fileName);
if (fileList.hasNext()) {
// found matching file - append text
var file = fileList.next();
var combinedContent = content;
file.setContent(combinedContent);
}
else {
// file not found - create new
folder.createFile(fileName, content);
}
}
}
The problem is that when I export the data its exporting with the empty lines and on the .txt shows up empty lines that i dont want to have, how i can make it? So I only export the lines that have content.
This is what the .txt looks like https://i.stack.imgur.com/wplZL.png
I think that the reason of your issue might be due to sheet.getRange('G3:G50'). In this case, even when the empty rows are included below the data range in the range of G3:G50, range.getValues() retrieves all rows of G3:G50. If you want to retrieve the values with the data range, how about the following modification?
From:
var range = sheet.getRange('G3:G50');
To:
var range = sheet.getRange('G3:G' + sheet.getLastRow());
And, when you want to remove all empty rows of the column "G", you can also use the following modification.
From:
var range = sheet.getRange('G3:G50');
var rows = range.getValues();
To:
var range = sheet.getRange('G3:G' + sheet.getLastRow());
var values = range.getValues().filter(([g]) => g.toString() != "");
References:
getLastRow()
filter()

How can I export to .csv with pipe delimiter

I use Google Sheets (spreadsheet) to combine article data for different sources for my Gambio shop.
To import the data I need the pipe symbol as delimiter / separator and " as text delimiter in a .csv file.
In the Google Sheets menu for exporting to .csv there are no Options.
Is there a way to export to .csv with pipe separators in Google Sheets?
There are several ways to export a spreadsheet and/or a sheet from Google Sheets. Exporting a sheet as a csv file is built-in to Google Sheets (File, Download, CSV).
In this case, the OP introduces two complications that are not catered for by the "standard" methods.
1) the fields to be delimited by the 'pipe' character (|), and
2) all string fields to be enclosed in double quotes.
There are several scripts on GitHub that offer automation of the process of saving a sheet as csv. export-named-sheet-as-csv.gs by Michael Derazon (https://gist.github.com/mderazon/9655893) is an example, and I used this as a basis for this code. However, these scripts follow the "normal" rules of using a comma as the field delimiter, and no special treatment of strings.
The following code will save the active sheet as a csv file, and provides for pipe field delimiters and double quotes around strings. These parameters can be dictated by the user by editing fields on the Parameters sheet as seen in this screenshot.
The script uses typeof to identify strings, and a function isValidDate noted by Dmytro Shevchenko in Detecting an “invalid date” Date instance in JavaScript.
/*
* script to export data in all sheets in the current spreadsheet as individual csv files
* files will be named according to the name of the sheet
* author: Michael Derazon
* source: https://gist.github.com/mderazon/9655893
* adapted by Ted Bell for https://stackoverflow.com/questions/49248498/how-can-i-export-to-csv-with-pipe-delimiter
*/
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{
name: "export as csv file",
functionName: "saveAsCSV"
}];
ss.addMenu("CSV Export", csvMenuEntries);
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssname = ss.getName();
var sheet = ss.getActiveSheet();
var sheetname = sheet.getSheetName();
//Logger.log("DEBUG: the name of the spreadsheet is "+ssname);//DEBUG
//Logger.log("DEBUG: the sheet name is "+sheetname);// DEBUG
//// create a folder from the name of the spreadsheet
var folder = DriveApp.createFolder(ssname.toLowerCase() + '_' + sheetname.toLowerCase().replace(/ /g, '_') + '_csv_' + new Date().getTime());
//Logger.log("DEBUG: the folder name is "+folder);//DEBUG
// append ".csv" extension to the sheet name
var fileName = ssname + '_' + sheetname + ".csv";
// convert all available sheet data to csv format
var csvFile = so_4225484202(fileName);
// create a file in the Docs List with the given name and the csv data
folder.createFile(fileName, csvFile);
Browser.msgBox('Files are waiting in a folder named ' + folder.getName());
}
function isValidDate(date) {
return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
function so_4225484202(filename) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var paramsheet = ss.getSheetByName("Parameters");
var linearray = [];
var rowdata = [];
var csv = "";
var fieldvalue = "";
var param = paramsheet.getRange(2, 2, 2);
var paramValues = param.getValues();
//Logger.log("DEBUG: parameters = "+param.getA1Notation());//DEBUG
var fieldDelimiter = paramValues[0][0];
var textDelimiter = paramValues[1][0];
//Logger.log("DEBUG: field delimiter: "+fieldDelimiter+", text delim: "+textDelimiter);//DEBUG
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
//Logger.log("DEBUG: lastColumn: "+lastColumn+", lastRow: "+lastRow);//DEBUG
// Get array of values in the Data Range
var rangeValues = rangeData.getValues();
// Loop through array and build values for csv
for (i = 0; i < lastRow; i++) {
for (j = 0; j < lastColumn; j++) {
var value = rangeValues[i][j];
var theType = typeof value;
if (theType === "object") {
var testdate = isValidDate(value);
//Logger.log("if typeof is object: testdate: "+testdate);//DEBUG
var testtype = typeof testdate;
if (testtype === "boolean") {
// variable is a boolean
//Logger.log("Its a date");//DEBUG
theType = "date";
} else {
//Logger.log("Its not a date");//DEBUG
}
}
if (theType === "string") {
value = textDelimiter + value + textDelimiter;
}
rowdata.push([value]);
};
//Logger.log("DEBUG: rowdata: "+rowdata);//DEBUG
csv += rowdata.join(fieldDelimiter) + "\n";
var rowdata = [];
};
//Logger.log("DEBUG: csv: "+csv);//DEBUG
return csv;
}
This spreadsheet contains sample data.
A sheet containing almost 1,000 records is processed and saved in about 5 seconds.
I actually didn't make it happen inside the Google world.
My workaround is to use an editor like Sublime Text to mark all pipe delimiters and replace them with semicolon to import in sheets.

Trouble Uncompressing Zip and then parsing CSV with Google Apps Script

Trying to create a Google Apps Script that reads emails from a specific email address and copy the contents of a CSV file into a Google sheet.
Problem is sometimes the files come in as zip attachments. I'm trying to work logic into the script to uncompress the zip if it's a zip attachment and then post the data to the Google sheet.
Currently getting the following error message: Cannot find function getDataAsString in object Blob.
Any ideas / recommendations for getting this to work with potential zip files would be great.
You can find my full code below:
function myFunction() {
var threads = GmailApp.search("from:testemail#example.com");
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
Logger.log(attachment.getContentType());
// Is the attachment a CSV file
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
Logger.log("Found a CSV file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
if (attachment.getContentType() === "application/zip") {
var sheet = SpreadsheetApp.getActiveSheet();
var files = Utilities.unzip(attachment);
Logger.log(files);
var newDriveFile = DriveApp.createFile(files[0]);
var csvData = Utilities.parseCsv(files.getDataAsString(), ",");
Logger.log("Found a ZIP file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}
Utilities.unzip will return array of blobs. So you need to refer the particular blob inside the array of blobs. Just modify the below code snippet.
var files = Utilities.unzip(attachment)[0];
Also, it is safe to mention the charset so that special characters are displayed properly.
var csvData = Utilities.parseCsv(attachment.getDataAsString('ISO-8859-1'), ",");
Entire Function:
function exportData() {
var threads = GmailApp.search("from:testemail#example.com");
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
Logger.log(attachment.getContentType());
// Is the attachment a CSV file
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString('ISO-8859-1'), ",");
Logger.log("Found a CSV file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
if (attachment.getContentType() === "application/zip") {
var sheet = SpreadsheetApp.getActiveSheet();
var files = Utilities.unzip(attachment)[0];
var csvData = Utilities.parseCsv(files.getDataAsString('ISO-8859-1'), ",");
Logger.log("Found a ZIP file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}