Not sure if any of you guys/girls out there that uses the NZBMatrix website API..
In short what I'm trying to do is build an Adobe Air Application,
using JavaScript, AJAX to connect to the API with a search query, this is all good.
When i receive the "request.responseText" back from the API with the 5 results
(can only be 5) I'm having trouble with the JavaScript split function trying to split them all out...
the return string is returned as follows:
NZBID:444027;
NZBNAME:test result 1;
LINK:nzbmatrix.com/nzb-details.php?id=444027&hit=1;
SIZE:1469988208.64;
INDEX_DATE:2009-02-14 09:08:55;
USENET_DATE:2009-02-12 2:48:47;
CATEGORY:TV > Divx/Xvid;
GROUP:alt.binaries.test;
COMMENTS:0;
HITS:174;
NFO:yes;
REGION:0;
|
NZBID:444028;
NZBNAME:another test;
LINK:nzbmatrix.com/nzb-details.php?id=444028&hit=1;
SIZE:1469988208.64; = Size in bytes
etc..etc..
the first Array should split each set of results using |
assign those 5 results to a new array.
the 2nd Array should split each value using :
assign those 12 results to new variables
ie: var nzbidtxt = array1[0]; which would echo like:
document.write(nzbidtxt); // ie: print "NZBID:"
the 3rd Array should split each variable from ;
assign those 12 values to the newly created array
ie: var nzbidValue = array2[0]; which would echo like:
document.write(nzbValue); // ie: print "444027"
so using both arrays I can display a listing of the posts returned..
in a nice usable format..
nzbid: 444027 // this will be used for direct download
nzbName: the name of the nzb
etc..etc..
the function i have been working on is below:
function breakNzbUrlResponse(text)
{
var place = new Array;
var place2 =new Array;
var place3 =new Array;
place[0] = text.indexOf('|');
place2[0] = text.indexOf(':');
place3[0] = text.indexOf(';');
var i = 1;
while(place[i-1] > 0 || i==1) {
place[i] = text.indexOf('|',place[i-1]+1);
place2[i] = text.indexOf(':',place2[i-1]+1);
if(place2[i] == -1)
{
place2[i] = text.length;
}
i++;
}
i=1;
var vars = new Array;
var values = new Array;
var retarray = new Array;
vars[0] = text.substr(0,place[0]);
values[0] = text.substr((place[0]+1),((place2[0]-place[0])-1));
retarray[vars[0]] = values[0];
while(i < (place.length-1) || i==1)
{
vars[i] = text.substr((place2[i-1]+1),((place[i]-place2[i-1])-1));
values[i] = text.substr((place[i]+1),((place2[i]-place[i])-1));
//alert('in loop\r\nvars['+i+'] is: '+vars[i]+'\r\nvalues['+i+'] is: '+values[i]);
retarray[vars[i]] = values[i];
i++;
}
return retarray;
}
This feels and looks like a very long winded process for this type..
all I want to do is basically assign a new variable to each return type
ie
var nzbid = array3[0];
which when split would reference the first line of the return string, NZBID:444027; where the value for NZBID would be 44027..
bit of a book going on, but the more info the better i suppose.
Thanks
Marty
You could probably cut out a significant number of lines of code by further utilizing split() instead of the manual dissections of the entries and using multidimensional arrays instead of repeatedly creating new arrays.
The logic would be:
ResultsArray = split by "|"
FieldArray = Each element of FieldArray split by ";"
ValueArray = Each element of FieldArray split by ":"
2 years later, it's sad that NZBMatrix is still using this horrible format. Here is how you can parse it.
//used to hold temporary key/value pairs
var tempKV = {};
//used to hold the search results
this.searchResults = [];
//The unformatted search results arrive in inResponse
//Remove whitespace and newlines from the input
inResponse = inResponse.replace(/(\r\n|\n|\r)/gm,"");
//search entries are delimited by |
var results = inResponse.split("|");
for(var i = 0; i < results.length; i++){
//key:value pairs in each search result are dlimited by ;
var pair = results[i].split(";");
for(var j = 0; j < pair.length; j++){
//keys and values are delimited by :
var kv = pair[j].split(":");
//normal key:value pairs have a length of 2
if(kv.length == 2){
//make sure these are treated as strings
//tempKV["key"] = "value"
tempKV["" + kv[0]] = "" + kv[1];
}
//Else we are parsing an entry like "http://" where there are multiple :'s
else if(kv.length > 2){
//store the first chunk of the value
var val = "" + kv[1];
//loop through remaining chunks of the value
for(var z = 2; z < kv.length; z++){
//append ':' plus the next value chunk
val += ":" + kv[z];
}
//store the key and the constructed value
tempKV["" + kv[0]] = val;
}
}
//add the final tempKV array to the searchResults object so long
//as it seems to be valid and has the NZBNAME field
if(tempKV.NZBNAME){
this.searchResults[i] = tempKV;
}
//reset the temporary key:value array
tempKV = {};
}
//all done, this.searchResults contains the json search results
Related
I'm adding values to a multidimensional array using loops
var leg_array = {};
var enc_array = [];
for (var c = 0; c < result.routes[0].legs.length; c++) {
leg_array[c] = {};
for (var b = 0; b < result.routes[0].legs[c].steps.length; b++) {
//var lat_lngs = result.routes[0].legs[c].steps[b].encoded_lat_lngs; //encoded polyline representation
var start_location_A = result.routes[0].legs[c].steps[b].start_location.A;
var start_location_F = result.routes[0].legs[c].steps[b].start_location.F;
var end_location_A = result.routes[0].legs[c].steps[b].end_location.A;
var end_location_F = result.routes[0].legs[c].steps[b].end_location.F;
enc_array[b] = start_location_A + "," + start_location_F + ":" + end_location_A + "," + end_location_F;
leg_array[c] = enc_array;
}
}
console.log(leg_array);
When i check the console log, the arrays in the first level of the multi dimensional array are identical.
How can i solve this? Values of enc_array are duplicate in every leg_array
e.g. leg_array[0] = enc_array, leg_array[1] = enc_array
enc_array is the same when the values should be different.
You are referencing the same array multiple times. If you want to create different arrays for each leg_array[c] value, use the Array.prototype.slice method instead:
leg_array[c] = enc_array.slice()
This will create a new copy of enc_array (in it's current form) to store in leg_array[c].
Of course, if you do that in the current location, it will set that same value multiple times (because it's inside the loop). Moving it to be inside the outer for loop will probably get the result you want.
So I found some info on this site on how to go about grabbing the value of the last index of an array. I have an Array that is of an unknown length. It builds based on a search of results. For example:
var custid = nlapiGetFieldValue('entity');
var custRecord = nlapiLoadRecord('customer', custid);
var itemPriceLineCount = custRecord.getLineItemCount('itempricing');
for (var i = 1; i <= itemPriceLineCount; i++) {
var priceItemId = [];
priceItemId = custRecord.getLineItemValue('itempricing', 'item', i);
if (priceItemId == itemId) {
var histCol = [];
histCol[0] = new nlobjSearchColumn('entity');
histCol[1] = new nlobjSearchColumn('totalcostestimate');
histCol[2] = new nlobjSearchColumn('tranid');
histCol[3] = new nlobjSearchColumn('trandate');
var histFilter = [];
histFilter[0] = new nlobjSearchFilter('entity', null, 'is', custid);
histFilter[1] = new nlobjSearchFilter('item', null, 'is', itemId);
var histSearch = nlapiSearchRecord('invoice', null, histFilter, histCol);
for (var h = 0; h <= histSearch.length; h++) {
var itemRate = new Array();
var histSearchResult = histSearch[h];
itemRate = histSearchResult.getValue('totalcostestimate');
}
}
}
Now when I use:
var last_element = itemRate[itemRate.length - 1];
It gives me the number of digits/placeholders in each element of the array. So as per my example I know my array holds the values of .00 and 31.24 because I put them there for a test. So last_element will result in 3 and 5. How can I grab the value 31.24 or the last element period? I need the value not the number of digits.
var itemRate = new Array();// Not sure what you intend to do with this array
var histSearchResult = histSearch[h];
itemRate = histSearchResult.getValue('totalcostestimate'); // but note `itemRate` is no more an array here. Its a variable having the value of `totalcostestimate` in string format
Now coming to your use case
/* you're trying to get the length of the string value and subtracting -1 from it.
So its very obvious to get those number of digits */
var last_element = itemRate[itemRate.length - 1]; // returns you that index value of the string
If you want to get the last array value of your search i.e histSearch
You may want to do something like this
var last_element = histSearch[histSearch.length-1].getValue('totalcostestimate');
As a side note it is always recommended to validate the returning value from a saved search result. Because on a successful search it returns you an array object on the other hand if no result founds it'll return you null.
//likely to get an error saying can't find length from null
for (var h = 0; h <= histSearch.length; h++) {
}
You can use something like this
// Never enter into the loop if it is null
for (var h = 0; histSearch!=null && h <= histSearch.length; h++) {
}
Good morning.
Very new coder with little background. I need to merge data from a google spreadsheet into an email, without using an add-on. I borrowed this code from a site and I'm able to produce an email but it will only pull from the first email address column. I need to send an email to both the manager and director. Their email address will be stored in two separate columns with unique labels. I can't change the spreadsheet data as the spreadsheet is storing responses pulled from a survey form that is already in progress (example column layout below):
Name / Email Address / Director Name / Director Email Address / Response 1 / Response 2 / etc...
Everything I've researched will send an email from one column, but not two, or a "cc".
Below is the borrowed code. Would very much appreciate any help on how to modify the code to send the "response" data to both the Manager and Director in one email.
kind regards,
KA
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 15);
var templateSheet = ss.getSheets()[1];
var emailTemplate = templateSheet.getRange("A1").getValue();
// Create one JavaScript object per row of data.
var objects = getRowsData(dataSheet, dataRange);
// For every row object, create a personalized email from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {
// Get a row object
var rowData = objects[i];
// Generate a personalized email.
// Given a template string, replace markers (for instance ${"First Name"}) with
// the corresponding value in a row object (for instance rowData.firstName).
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = "Data Survey";
MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText);
}
}
// Replaces markers in a template string with values define in a JavaScript data object.
// Arguments:
// - template: string containing markers, for instance ${"Column name"}
// - data: JavaScript object with values to that will replace markers. For instance
// data.columnName will replace marker ${"Column name"}
// Returns a string without markers. If no data is found to replace a marker, it is
// simply removed.
function fillInTemplateFromObject(template, data) {
var email = template;
// Search for all the variables to be replaced, for instance ${"Column name"}
var templateVars = template.match(/\$\{\"[^\"]+\"\}/g);
// Replace variables from the template with the actual values from the data object.
// If no value is available, replace with the empty string.
for (var i = 0; i < templateVars.length; ++i) {
// normalizeHeader ignores ${"} so we can call it directly here.
var variableData = data[normalizeHeader(templateVars[i])];
email = email.replace(templateVars[i], variableData || "");
}
return email;
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// The code below is reused from the 'Reading Spreadsheet data using JavaScript Objects'
// tutorial.
//
//////////////////////////////////////////////////////////////////////////////////////////
// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
// - sheet: the sheet object that contains the data to be processed
// - range: the exact range of cells where the data is stored
// - columnHeadersRowIndex: specifies the row number where the column names are stored.
// This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() - 1;
var numColumns = range.getEndColumn() - range.getColumn() + 1;
var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
return getObjects(range.getValues(), normalizeHeaders(headers));
}
// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
// - data: JavaScript 2d array
// - keys: Array of Strings that define the property names for the objects to create
function getObjects(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}
// Returns an Array of normalized Strings.
// Arguments:
// - headers: Array of Strings to normalize
function normalizeHeaders(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}
// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
// - header: string to normalize
// Examples:
// "First Name" -> "firstName"
// "Market Cap (millions) -> "marketCapMillions
// "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
function normalizeHeader(header) {
var key = "";
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == " " && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum(letter)) {
continue;
}
if (key.length == 0 && isDigit(letter)) {
continue; // first character must be a letter
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}
// Returns true if the cell where cellData was read from is empty.
// Arguments:
// - cellData: string
function isCellEmpty(cellData) {
return typeof(cellData) == "string" && cellData == "";
}
// Returns true if the character char is alphabetical, false otherwise.
function isAlnum(char) {
return char >= 'A' && char <= 'Z' ||
char >= 'a' && char <= 'z' ||
isDigit(char);
}
// Returns true if the character char is a digit, false otherwise.
function isDigit(char) {
return char >= '0' && char <= '9';
}
According to the documentation : Mail App, the recipent represents the addresses of the recipients, separated by commas
So in order to send to several recipents, just make a string separated by comma:mike#example.com, mike2#example.com
You could pick the rows you want and do something like this:
MailApp.sendEmail(rowData[0].emailAddress + ',' + rowData[1].emailAdress, emailSubject, emailText);
For a homework assignment, I have to make a web page that has a text area. The user inputs some text, hits the analyse button, and the output is supposed to be a list of the frequency of words of a given number of characters. For example, "one two three" would be two words of three characters and one word of five characters. The text area works fine, but I can"t seem to get the output to appear.
Here is the html:
<body>
<textarea id="text" rows="26" cols="80"></textarea>
<form>
<input type="button" id="analyse" value="Analyse Text">
</form>
<div id="output"></div>
</body>
The JavaScript file has 6 functions. The first function returns an array that stores the number of characters for each word in the input textarea:
function getWordInfo() {
var text = document.getElementById("text").value;
//the variable wordArray uses a regular expression to parse the input
var wordArray = text.split("/\w\w+/g");
var arrayLength = wordArray.length;
var charArray = [];
for (var i = 0; i < arrayLength; i++) {
var splitWord = wordArray[i].split("");
var wordLength = splitWord.length;
charArray.push(wordLength);
}
return charArray;
}
The second function is a simple object constructor that has a name property and a count property. The count property has a default value of 0.
function obCon(name,count) { //object constructor
this.name = name;
this.count = count;
count = typeof count !== "undefined" ? count : 0;
}
The third function returns an array that stores word objects. Each object has a name property and a count property. The name property is the number of characters in a word. The count property counts how many times an object with a given name property appears.
function arCon() { //array constructor
var charNum = getWordInfo();
var arrayLength = charNum.length;
var obArr = [];
for (var i = 0; i < arrayLength; i++) {
if (typeof obArr.indexOf( newOb.name === charNum[i] ) != "undefined" ) { // checks if the object needed exists
obArr.indexOf( newOb.name === charNum[i] ).count = obArr.indexOf( newOb.name === charNum[i] ).count + 1;
}else{
var newOb = new obCon(charNum[i]);
newOb.count = newOb.count + 1;
obArr.push(newOb);
}
}
return obArr;
}
The fourth function is a string formatter, meant format the objects from arCon into a single readable string, then store it in an array.
function formatter() {
var strAr = arCon();
var arrayLength = strAr.length;
var formatStr = [];
for (var i = 0; i < arrayLength; i++) {
var str = "Number of characters: " + strAr[i].name + ", Number of words with this length: " + strAr[i].count;
formatStr.push(str);
}
return formatStr;
}
The fifth function is called for an event handler, meant to handle the click of the analyse button. On click, it is meant to get the div tag, get the formatted array, then loop though each element in the array, where it creates a p element element, pulls the formatted string, sets the p element value to the formatted string, then appends the p element to the div tag.
function analyseButtonClick() {
var div = document.getElementById("output");
var str = formatter();
var arrayLength = str.length;
for (var i = 0; i < arrayLength; i++) {
var par = document.createElement("p");
var format = str[i];
par.value = format;
div.appendChild(par);
}
}
The sixth function is an init function that handles the button click.
function init() {
var button = document.getElementById("analyse");
button.onclick = analyseButtonClick;
}
window.onload = init;
I have run this though a validator, and it shows me that there are no syntax errors, so it must be a logic error. However, all the functions seem to do what they are supposed to do, so I am not sure where I went wrong.
edit1: ok, have replaced the third function with four new functions. a function that returns the highest number in the array returned by getWordInfo, a function that constructs objects with name properties from 2 up to that number, a function that update the count properties of the objects, and a function that removes unused objects. here they are:
function maxNum() {
var array = getWordInfo();
var num = Math.max.apply(Math, array);
return num;
}
function objArrCon() { //object array constructor
var num = maxNum();
var array1 = [];
for (var i = 2; i === num; i++) {
var myObj = new objCon(i,0);
array1.push(myObj);
}
return array1;
}
function objArrParse() { //updates the object with word info
var array1 = getWordInfo();
var array2 = objArrCon();
var loopLength1 = array1.length;
var loopLength2 = array2.length;
for (var i = 0; i < loopLength1; i++) {
for (var m = 0; m < loopLength2; m++) {
if (array2[m].name === array1[i]) {
array2[m].count++;
}
}
}
return array2;
}
function objArrTrun() { //removes unused objects
var array1 = objArrParse();
var loopLength = array1.length;
for (var i = 0;i < loopLength; i++) {
if (array1[i].count === 0) {
array.splice(i, array1);
}
}
return array1;
}
still does not work, but im getting there!
I have written this in jQuery because 1) it's not my homework assignment and 2) it would be good practice (for you) to translate it back into normal JavaScript. You'll need to rewrite the event handler, along with the two getters/setters ($("text area").val() and $("tbody").append()).
Your main problem is that you have made your solution too complicated! If all you want to do is display the number, Y, of words with length, X, then you should do the following:
Grab the value of the text area and store in text
Remove all non-alphanumeric characters.
Split the text string wherever one or more spaces is present and store it in text
Loop through the array and map each array element, based on its length, to wordMap
Loop through wordMap and append it to wherever in the DOM you want the results to be
fiddle
JavaScript
$("#analyze").click(function () {
var text = $("textarea").val().replace(/[^\d\w ]+/g," ").split(/[ ]+/);
// this grabs the value of the text area, replaces all non-numerical
// and non-alphabetical characters with "", and then splits it into an array
// wherever one or more spaces is present.
var wordMap = {};
// makes an object that will be used as an associative array
text.forEach(function (d) {
// loops through the array
// if there is no key called d.length in wordMap
if (!wordMap[d.length])
wordMap[d.length] = 1; // set its count to one
else
wordMap[d.length]++; //otherwise, increment it
})
// loop through all the properties of wordMap
for (var x in wordMap) {
$("tbody").append("<tr><td>" + x + "</td><td>"
+ wordMap[x] + "</td></tr");
}
console.log(wordMap);
})
HTML
<textarea placeholder="type something..."></textarea>
<button id="analyze">Click to analyze</button>
<div id="results">
<table>
<thead>
<th>Length of Word</th>
<th>Number of Occurrences</th>
</thead>
<tbody>
</tbody>
</table>
</div>
I'm using JavaScript (prototype and ajax), PHP and MySQL to display some values from a database in textfields and a dropdown list, but I ran into a problem with JavaScript.
Every time a user clicks on an option in a list the values should update. These values are pushed in an array, but even after clearing it or setting its length to 0, the values get pushed to the end of how the array was before.
It all works fine the first time, but after that the array keeps on getting bigger and it adds more and more values to the dropdown list. Here's the code:
function artSelect(art){
//perform an Ajax request
var artRequest = new XMLHttpRequest();
//If the output is returned successfully, add it in the document
artRequest.onreadystatechange = function() {
if (artRequest.readyState==4) {
//Get the text
var text = artRequest.responseText;
//Create an array
var x = new Array();
//Create a variable for storing the position of the last semicolon (the values are seperated by semicolons)
var lastSemCol = 0;
//Split the text by scanning for semicolons and put them in an array
for (var i=0; i<text.length; i++) {
//If the current char is ";"
if (text[i] === ";") {
//Create a substring of the chars between the last ; and current ;
var value = text.substr(lastSemCol + 1, i-lastSemCol-1);
//Add the value to the array
Array.prototype.push(value);
lastSemCol = i;
}
}
//Set the values in the document
$("beschrijving").value = x[1];
$("kleur").value = x[2];
$("voorraad").value = x[3];
$("prijs").value = x[4];
$("srtc").value = x[5];
//Set the departments
for (var i=6; i < Array.prototype.size(x); i++) {
var option = document.createElement("option");
option.text = x[i];
$("afd").add(option);
}
//Clear the array (no effect)
x.clear();
x.length = 0;
x = new Array();
}
};
artRequest.open("GET", "server.php?mode=getArtikel&artikel=" + selected.value.substr(0,7), true);
artRequest.send(null);
}