I have a file that looks like so:
QUERY:1
DATABASE:geoquery
NL:What are the capitals of the states that border the most populated states?
SQL:something
QUERY:2
DATABASE:geoquery
NL:What are the capitals of the states bordering New York?
SQL:SELECT state.Capital FROM state JOIN borderinfo ON state.State_Name = borderinfo.State_Name
WHERE borderinfo.Border = 'New York'
QUERY:3
DATABASE:geoquery
NL:Show the state capitals and populations.
SQL:SELECT state.Capital, state.Population FROM state
etc...
The person generating this file refuses to give it to me in a usable format like say, XML or JSON. So I am parsing it a couple of times with REGEX to get results I want.
Strip off Databases to populate select list (works fine):
$.get('inputQueryExamples.txt',
function(data){
var string = data;
var dbDynamo ='';
dbExp = new RegExp('(DATABASE:.*)','gm');
dbDynamo = string.match(dbExp);
cleanBreaks = new RegExp('(\r?\n|\r)','gm');
stringNow = dbDynamo.toString();
//console.log(dbDynamo);
dbDynamo = dbDynamo.map(function(el){return el.replace('DATABASE:','');});
var outArray = [];
for(i=0; i < dbDynamo.length; i++){
if ($.inArray(dbDynamo[i],outArray)== -1){
outArray.push(dbDynamo[i]);
}
}
dbDynamo = outArray.sort();
var options = '';
for(i=0; i<dbDynamo.length; i++){
options += '<option value="' + dbDynamo[i] + '">' + dbDynamo[i] + '</option>';
};
$(select).append(options);
});
The problem comes when I parse a second time to get all of the strings associated with a specific database. I end up with a linebreak in front of every string so that when I fill a textarea with the autocomplete text it starts on the second line:
Array [ "
NL:Show company with complaint against Debt collection product.,DATABASE:consumer", "
NL:Show issues and dates of complaints about HSBC companies.,DATABASE:consumer", "
NL:Show companies, issues and dates with consumer concerns.,DATABASE:consumer", "
NL:Show issues and companies with complaints in MA state." ]
$(document).ready(function(){
$.get('inputQueryExamples.txt',function(data){
var queryString = data;
var cleanString = "";
var db = '';
$('#database-list').change(function(){
db = $('#database-list').val();
// /(^DATABASE:.*\r\n)(^NL.*)/gm
// http://regex101.com/r/mN4hS2
regex = new RegExp('(^DATABASE:'+ db +'\r\n)(^NL.*)' ,'gm');
cleanString = queryString.match(regex);
//console.log(cleanString);
//cleanBreaks = new RegExp('(\r\n|\r|\n)(^NL.*)','gm');
//stringNow = cleanString.toString();
//var dirtyString
//dirtyString = stringNow.match(cleanBreaks);
//console.log(dirtyString);
var nlString = cleanString.map(function(el) {return el.replace('DATABASE:' + db,'');});
nlString = nlString.map(function(el){return el.replace('NL:',''); });
//nlString = nlString.map(function(el){return el.replace('\\r','').replace('\\n','');});
console.log(nlString.pop());
$('#query-list').autocomplete({
source:nlString,
});
}); // end change
I have tried about everything I can think of to get rid of the linebreaks without success. Any ideas would be appreciated. Unfortunately the one where the server side just gives me data in a usable format is not viable. There is a lot of extra code in this just to give you an idea of what I have tried. I have commented out useless things. Thanks in advance.
It would make sense to use JavaScript to parse the data-structure you are given into a JavaScript object first, then you can more easily work with the data.
Here is a jsfiddle that demonstrates parsing your data into a JavaScript object. Below is the relevant code that does the parsing:
var datasources = {};
var parseData = function(block) {
var db = block.match(/DATABASE:(.*)/)[1];
var dbdata = {id: 0, nl: "", sql: ""};
if (!datasources[db]) {
datasources[db] = [];
}
dbdata.id = block.match(/QUERY:(.*)/)[1];
dbdata.nl = block.match(/NL:(.*)/)[1];
dbdata.sql = block.match(/SQL:(.*)/)[1];
datasources[db].push(dbdata);
};
var parseBlocks = function(data) {
var result = data.split('\n\n');
for(var i=0; i < result.length; i++) {
parseData(result[i]);
};
};
Thanks for the very thoughtful and elegant approach. I continued the brute force approach.
replace:
nlString = nlString.map(function(el){return el.replace('NL:',''); });
with:
nlString = nlString.map(function(el){return el.replace('NL:','').trim(); });
Related
Hello stackoverflow community,
I want to create a script to search a google sheet by name, as this file will be deleted at the end of the script. A new file will be uploaded to google drive automatically every week. This will be the basis for the script that will be running weekly.
The code runs fine, but returns undefined in the 4 output cells.
Example Data from a row in the Spreadsheet "LocafoxInventoryData_Automatic":
1||5b8ff4fc3e578c005487dcd5|60.0000|38.6300|19.0000|||2.0000
I would like to retrieve the last number in the above string. (after the last " | " )
I hope someone can help me out. The strings being searched for are the ids of the products: In the above sample "5b8ff4fc3e578c005487dcd5". This id can only be found twice in the sheet. I want to always retrieve the first one. The differnce between the first and the second product IDs are the first number in the string. There are "1" and "2".
function getData() {
var files = DriveApp.getFilesByName('LocafoxInventoryData_Automatic');
while (files.hasNext()) {
var file = files.next();
var id = file.getId()
}
var sheetData = SpreadsheetApp.openById(id).getActiveSheet().getDataRange().getValues();
var sspre = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vorlage");
var searchString1 = sspre.getRange('I7').getValue();
var searchString2 = sspre.getRange('I8').getValue();
var searchString3 = sspre.getRange('I9').getValue();
var searchString4 = sspre.getRange('I10').getValue();
for(var i=0;i<sheetData;i++)
{
//Column 1 should be searched
if(sheetData[i][0].search(searchString1)!=-1)
{
var rowData1 = sheetData[i];
return rowData1;
}
else if(sheetData[i][0].search(searchString2)!=-1)
{
var rowData2 = sheetData[i];
return rowData2;
}
else if(sheetData[i][0].search(searchString3)!=-1)
{
var rowData3 = sheetData[i];
return rowData3;
}
else if(sheetData[i][0].search(searchString4)!=-1)
{
var rowData4 = sheetData[i];
return rowData4;
}
}
sspre.getRange('D7').setValue(rowData1);
sspre.getRange('D8').setValue(rowData2);
sspre.getRange('D9').setValue(rowData3);
sspre.getRange('D10').setValue(rowData4);
file.setTrashed(true);
}
Returning Partial Row Data with Regex
Okay this is working for me. I have a file named 'LocafoxInventoryData_Automatic' which is a spreadsheet with one sheet. I look for files with that name and if more than one is found I throw error so that you can figure out which one you want.
I then open up the file as a SpreadSheet with openById. I get the product id from the Vorlage sheet column I7,8,9,10 and I wrap them with a regular expression that looks like this ^1\|\|cw8vtfxa5owglp03btv22g9d.\|\|\|(.)$ . Although in the code the backslashes \ have to be \\ double backslashed which took me a while to figure out.
So that get's the numbers at the end and I put them into Vorlage column D7,8,9,10. And then I set the file isTrashed to true. I don't know if you want to return the data so I left the object in there but commented them out. I also removed all of the else ifs.
function getData() {
var filename='LocafoxInventoryData_Automatic';
var files = DriveApp.getFilesByName(filename);
var n=0;
while (files.hasNext()) {
var file = files.next();
var id = file.getId();
n++;
}
if(n>1){throw(Utilities.formatString('Error: More than file named %s', filename));}//Will present an error if there is more than one file
if(id){
var sheetData = SpreadsheetApp.openById(id).getActiveSheet().getDataRange().getValues();//I assumed no headers in this file
var sspre = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vorlage");
var re1 = new RegExp('^1\\|\\|' + sspre.getRange('I7').getValue() + '.*\\|\\|\\|(.*)$','i');
var re2 = new RegExp('^1\\|\\|' + sspre.getRange('I8').getValue() + '.*\\|\\|\\|(.*)$','i');
var re3 = new RegExp('^1\\|\\|' + sspre.getRange('I9').getValue() + '.*\\|\\|\\|(.*)$','i');
var re4 = new RegExp('^1\\|\\|' + sspre.getRange('I10').getValue() + '.*\\|\\|\\|(.*$)','i');
for(var i=0;i<sheetData.length;i++){
var rD1=re1.exec(sheetData[i][0]);
if(rD1) {
var rowData1 = rD1[1];
}
var rD2=re2.exec(sheetData[i][0]);
if(rD2) {
var rowData2 = rD2[1];
}
var rD3=re3.exec(sheetData[i][0]);
if(rD3) {
var rowData3 = rD3[1];
}
var rD4=re4.exec(sheetData[i][0]);
if(rD4) {
var rowData4 = rD4[1];
}
}
//var rObj={rowData1:rowData1,rowData2:rowData2,rowData3:rowData3,rowData4:rowData4};
sspre.getRange('D7').setValue(rowData1);
sspre.getRange('D8').setValue(rowData2);
sspre.getRange('D9').setValue(rowData3);
sspre.getRange('D10').setValue(rowData4);
file.setTrashed(true);
//return rObj;
}
}
Regular Expression exec method
RegExp
By the way it's quite helpful with sort of a problem to have your own regex tester written in the same language you happen to be developing in. I'm sorry it took me so long. If you run into additional problems let me know.
From, a google spreadshhet, I'm trying to collect records from Zoho.
I've tested this code:
var urlgetRecords = 'https://crm.zoho.com/crm/private/json/Leads/getRecords?newFormat=1&authtoken=00000&scope=crmapi&selectColumns=Leads(First Name,Last Name,Email)&fromIndex=1&toIndex=2&sortColumnString=First Name&sortOrderString=desc';
var jsonResponse = UrlFetchApp.fetch(urlgetgetRecords);
This is what obtain:
{"response":{"result":{"Leads":{"row":[{"no":"1","FL":[{"content":"1412559000000441145","val":"LEADID"},{"content":"Víctor","val":"First
Name"},{"content":"Aguilera Moreno","val":"Last
Name"},{"content":"v-aguilera#hotmail.com","val":"Email"}]},{"no":"2","FL":[{"content":"1412559000000308001","val":"LEADID"},{"content":"Victor","val":"First
Name"},{"content":"Porta","val":"Last
Name"},{"content":"vporta#test.es","val":"Email"}]}]}},"uri":"/crm/private/json/Leads/getRecords"}}
Please, How can write every row in this response in a spreadsheet?
Thank you very much in advance :)
The Sandy Good's code is perfect.
I've had to add two more lines.
Finally the code that works is:
var urlgetRecords = 'https://crm.zoho.com/crm/private/json/Leads/getRecords?newFormat=1&authtoken=' + authToken + '&scope=crmapi&selectColumns=Leads(First Name,Last Name,Email)&fromIndex=1&toIndex=2&sortColumnString=First Name&sortOrderString=desc';
var jsonResponse = UrlFetchApp.fetch(urlgetRecords);
var jsonText = jsonResponse.getContentText();
var objetoFinal = JSON.parse(jsonText);
writeZohoToSheet(objetoFinal);
Thank you very much for your help #SandyGood
Write ZOHO data to Google spreadsheet. To use the code below, edit the sheet tab name in the getSheetByName('Sheet2') method to the sheet tab where you want the data to be appended to.
I've tested this code and it works:
function writeZohoToSheet(zohoDataObject) {
var zohoDataObject = {"response":
{"result":
{"Leads":
{"row":
[{"no":"1","FL":[
{"content":"12345678IDNumber","val":"LEADID"},
{"content":"Víctor","val":"First Name"},
{"content":"Aguilera Moreno","val":"Last Name"},
{"content":"v-agEmailTest#hotmail.com","val":"Email"}]
},
{"no":"2","FL":[
{"content":"987654321IDNumber","val":"LEADID"},
{"content":"Victor","val":"First Name"},
{"content":"Porta","val":"Last Name"},
{"content":"someEmail#test.es","val":"Email"}]
}
]
}
},"uri":"/crm/private/json/Leads/getRecords"}};
var rows = zohoDataObject.response.result.Leads.row;
Logger.log('rows: ' + rows);
Logger.log('rows.length: ' + rows.length);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('Sheet2');
var array = [], thisRow, thisContent, innerObj;
for (var r in rows) {
array = []; //reset
thisRow = rows[r];
thisContent = thisRow.FL;
array.push(r);
for (var i=0;i<thisContent.length;i+=1) {
innerObj = thisContent[i];
array.push(innerObj.val);
array.push(innerObj.content);
};
sh.appendRow(array);
};
};
You would call the function with:
writeZohoToSheet(jsonResponse);
Remove the "hard coded" object literal, or comment it out in order to pass in the retrieved object.
I'm working with some CSV data. Right now the CSV has a column called 'characteristic' which is one of three types, and a column called 'value', which contains the numerical value for the characteristic.
I'd like to change the structure of the data so that the columns are the characteristics themselves, and the values fall directly under those columns.
Here are screenshots of the tables, for clarity:
Currently:
What I'd like:
I changed things manually to give an example. The actual table I'll need to change is thousands of lines, so I'm hoping I can do this programmatically in some way.
The reason I need to restructure is that I need to transform the CSV to JSON, and the JSON needs to look like this:
[
{
"country":"afghanistan",
"iso3":"afg",
"first_indicator":3,
"second_indicator":5,
"third_indicator":3
},
{
"country":"united states",
"iso3":"usa",
"first_indicator":8,
"second_indicator":6,
"third_indicator":7
},
{
"country":"china",
"iso3":"chn",
"first_indicator":6,
"second_indicator":0.7,
"third_indicator":2
}
]
So - is there any way to take my CSV as it is now (first screenshot), and transform it to the JSON I want, without doing it all manually?
I've done a lot of searching, and I think maybe I just don't know what to search for. Ideally I would use javascript for this, but any suggestions welcome.
Thank you.
I made a JSFiddle for you, something like this should be what you want.
JavaScript
function Country(name, short){
this["country"] = name;
this["iso3"] = short;
}
function getCountryByName(name) {
for(var i = 0; i < countries.length; i++){
var country = countries[i];
if(country["country"] == name){
return country;
}
}
return null;
}
var csv = "country,shortname,characteristics,value\nafghanistan,afg,first_characteristic,3\nunited states,usa,first_characteristic,8\nchina,chn,first_characteristic,6\nafghanistan,afg,second_characteristic,5\nunited states,usa,second_characteristic,6\nchina,chn,second_characteristic,0.7\nafghanistan,afg,third_characteristic,3\nunited states,usa,third_characteristic,7\nchina,chn,third_characteristic,2"
var rows = csv.split("\n");
var countries = [];
if(rows.length > 0){
var header = rows[0];
var columns = header.split(",");
var countryIndex = columns.indexOf("country");
var shortnameIndex = columns.indexOf("shortname");
var characteristicsIndex = columns.indexOf("characteristics");
var valueIndex = columns.indexOf("value");
for(var i = 1; i < rows.length; i++) {
var row = rows[i];
var columns = row.split(",");
var name = columns[countryIndex];
var short = columns[shortnameIndex];
var characteristic = columns[characteristicsIndex];
var value = columns[valueIndex];
var country = getCountryByName(name);
if(!country){
country = new Country(name, short);
countries.push(country);
}
country[characteristic.replace("characteristic", "indicator")] = +value;
}
}
console.log(countries);
console.log(JSON.stringify(countries));
Output from the last line is this:
[{"country":"afghanistan","iso3":"afg","first_indicator":"3","second_indicator":"5","third_indicator":"3"},
{"country":"united states","iso3":"usa","first_indicator":"8","second_indicator":"6","third_indicator":"7"},
{"country":"china","iso3":"chn","first_indicator":"6","second_indicator":"0.7","third_indicator":"2"}]
My suggestion is to convert the CSV to JSON first. You can use an online tool.
When you have the JSON you can write a Javascript code to modify the JSON in the format you want.
I'm trying to write one row of data into a Google Cloud SQL database, using a prepared statement as described here:
https://developers.google.com/apps-script/guides/jdbc
I have the data stored in an object called valuesByTitle, which looks like this:
{NAME: 'fun event', LOCATION: '123 Main St.'}
The data is inserted into the SQL table if I write everything out like this:
var conn = getConnection(); // connects to db
var stmt = conn.prepareStatement('INSERT INTO events '
+ '(NAME, LOCATION) values (?, ?)');
stmt.setString(1, valuesByTitle['NAME']);
stmt.setString(2, valuesByTitle['LOCATION']);
stmt.execute();
}
However, I would like to automate the process, so I don't have to change the code each time the variables change.
I have two new variables, one for the column names and one for a set of place holders (e.g. "?") for the insert statement.
var columns = Object.keys(valuesByTitle);
var placeholders = columns.map(function(column) {
return "?";
};
Using these, this prepared statement should automatically insert whatever is in the valuesByTitle object (assuming all the values are string values):
var conn = getConnection();
var stmt = conn.prepareStatement("INSERT INTO events (" + columns.join(",") + ") VALUES (" + placeholders.join(",") + ")");
for (i = 0; i < columns.length; i++) {
stmt.setString(i+1, valuesByTitle[columns[i]]);
}
stmt.execute();
For some reason, it's not inserting the data. Surprised not to find any examples either. Is the logic off or is it just not possible to do?
Thanks.
All your code is OK, you simply forgot to close the map() bracket i.e.
var columns = Object.keys(valuesByTitle);
var placeholders = columns.map(function(column) {
return "?";
};
should be
var columns = Object.keys(valuesByTitle);
var placeholders = columns.map(function(column) {
return "?";
});
(note the ending bracket after return "?";})
I currently have the bellow code to get some data from an xml feed.
var title = []
var start = []
var end = []
var xml = result;
var channel = xml.split('<channel')[1].split('>')[0].split('"')[1]
var xmlLength = xml.split("<programme>").length - 1;
for (var i = 0; i < xmlLength; i++) {
var event = xml.split("<event>")[i + 1].split("</event>")[0];
title[i] = programme.split("<title>")[1].split("</title>")[0];
var rs = programme.split("<start>")[1].split("</start>")[0].split(/\-|\s/);
var re = programme.split("<end>")[1].split("</end>")[0].split(/\-|\s/);
start[i] = new Date(rs.slice(0, 3).join('/') + ' ' + rs[3]);
end[i] = new Date(re.slice(0, 3).join('/') + ' ' + re[3]);
}
setListView(event, start, end, channel)
This currently works but it doesn't seem very efficient. I wonder if there is a better way of doing it.
Well, it looks like you should be using the classes in the Windows.Web.Syndication namespace as it looks like you are doing RSS related things, but you could also use the raw XML API's as well.
It seems like you are trying to parse the XML on your own. Have you considered using jQuery.parseXML()?
Check it out here: http://api.jquery.com/jQuery.parseXML/