Reputation: 103
I have a .csv file with 3000+ lines posted to a GDrive folded every morning, and I need to import data from that .csv into an existing Spreadsheet.
I had the following script that worked perfectly for a while, but it's been failing recently with the "Exception: Could not parse text." error. I triple-checked the .csv and confirmed the delimiter is correct.
function importOpps() {
var file = DriveApp.getFilesByName("Opportunity Report.csv").next();
var csvString = file.getBlob().getDataAsString()
var sanitizedString = csvString.replace(/(["'])(?:(?=(\\?))\2[\s\S])*?\1/g, function(e){return e.replace(/\r?\n|\r/g, ' ') });
Logger.log(sanitizedString)
var csvData = Utilities.parseCsv(sanitizedString);
var sheet = SpreadsheetApp.getActive().getSheetByName('opp');
sheet.getRange("A:AM").clear();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
I tried to find some workarounds and came across the following solution, which works for my case, but it takes forever to run.
function importData() {
var fSource = DriveApp.getFolderById('1Q3YU044I4g6SC3sRA37Gd3ezSJU5-O-i'); // reports_folder_id = id of folder where csv reports are saved
var fi = fSource.getFilesByName('SF Opportunity Report.csv'); // latest report file
var ss = SpreadsheetApp.openById('1E1RMG45Vtt0_gilDMnLTfWML_y4MSLqmH1dbCkL0UTM'); // data_sheet_id = id of spreadsheet that holds the data to be updated with new report data
if ( fi.hasNext() ) { // proceed if "report.csv" file exists in the reports folder
var file = fi.next();
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv); // see below for CSVToArray function
var newsheet = ss.insertSheet('NEWDATA'); // create a 'NEWDATA' sheet to store imported data
// loop through csv data array and insert (append) as rows into 'NEWDATA' sheet
for ( var i=0, lenCsv=csvData.length; i<lenCsv; i++ ) {
newsheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
/*
** report data is now in 'NEWDATA' sheet in the spreadsheet - process it as needed,
** then delete 'NEWDATA' sheet using ss.deleteSheet(newsheet)
*/
// rename the report.csv file so it is not processed on next scheduled run
file.setName("report-"+(new Date().toString())+".csv");
}
};
// http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.
function CSVToArray( strData, strDelimiter ) {
// Check to see if the delimiter is defined. If not,
// then default to COMMA.
strDelimiter = (strDelimiter || "\t");
// Create a regular expression to parse the CSV values.
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [[]];
// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;
// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec( strData )){
// Get the delimiter that was found.
var strMatchedDelimiter = arrMatches[ 1 ];
// Check to see if the given delimiter has a length
// (is not the start of string) and if it matches
// field delimiter. If id does not, then we know
// that this delimiter is a row delimiter.
if (
strMatchedDelimiter.length &&
(strMatchedDelimiter != strDelimiter)
){
// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );
}
// Now that we have our delimiter out of the way,
//let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]){
// We found a quoted value. When we capture
// this value, unescape any double quotes.
var strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
var strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
// Return the parsed data.
return( arrData );
};
Any idea what can be wrong with the first script? In the .csv file, I have a field with users` comments so I assume that it may be that some special characters were used in that field breaking the parseCSV(). I am struggling to find the root cause of the issue. I am not good at code, so I would appreciate any help on this.
Upvotes: 1
Views: 1438
Reputation: 201378
I believe your goal is as follows.
I have my .csv in the GDrive and not as a link.
, you want to retrieve the CSV data from a file and put to a Spreadsheet.I thought that this sample script might be useful. But from your comment, I could know that you want to retrieve the CSV data from a file on Google Drive. This sample script retrieves the CSV data from a URL. For your situation, I modify this sample script for your situation. So this modified script can be used for the CSV data retrieved from Google Drive.
Before you use this script, please enable Sheets API at Advanced Google services. And please modify your script as follows.
function importOpps() {
var file = DriveApp.getFilesByName("Opportunity Report.csv").next();
var csvString = file.getBlob().getDataAsString()
var sanitizedString = csvString.replace(/(["'])(?:(?=(\\?))\2[\s\S])*?\1/g, function(e){return e.replace(/\r?\n|\r/g, ' ') });
Logger.log(sanitizedString)
var csvData = Utilities.parseCsv(sanitizedString);
var sheet = SpreadsheetApp.getActive().getSheetByName('opp');
sheet.getRange("A:AM").clear();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
function importOpps() {
var file = DriveApp.getFilesByName("Opportunity Report.csv").next();
var csvString = file.getBlob().getDataAsString();
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('opp');
sheet.getRange("A:AM").clear();
SpreadsheetApp.flush();
var req = { pasteData: { data: csvString, delimiter: ",", coordinate: { sheetId: sheet.getSheetId() } } };
Sheets.Spreadsheets.batchUpdate({requests: [req]}, ss.getId());
}
delimiter: ","
.Upvotes: 2