Use Regex to fetch data - javascript

The regex I have made fetches itemlist from opts.taskDetails.order_details.
I want to optimize the regex/any other better regex to get the following data as is shown in the above image.
(which can be 1 item list or multiple).
Also apart from fetching the item details I also want to fetch data which is left after fetching items list from opts.taskDetails.order_details below.
Tipo de papa: -\nPapa Amarilla Tumbay S/0.00\n Adicional : - Quesp cheddar S/0.00\n Agrega Bebida: - Fanta 400 ml S/0.00\n
Salsas: - Mayonesa S/0.00\n - Ketchup S/0.00\n - Golf S/0.00\n - Guacamole S/0.00\n - Ají S/0.00\n - Tártara S/0.00\n - Mayo-aji S/0.00\n
CODE
var opts = {
"items": [{
"mail_parser_label": "order_details",
"label": "order_details",
"data_type": "Table",
"app_side": "0",
"required": 0,
"value": 1,
"data": {
"head": [{
"mail_parser_label": "Detalle",
"label": "Detalle",
"type": "text",
"arth": " ",
"id": 0,
"show": 1,
"app_side": 0,
"required": 0
}, {
"mail_parser_label": "Cantidad",
"label": "Cantidad",
"type": "text",
"arth": " ",
"id": 1,
"show": 1,
"app_side": 0,
"required": 0
}, {
"mail_parser_label": "Unidad",
"label": "Unidad",
"type": "text",
"arth": " ",
"id": 2,
"show": 1,
"app_side": 0,
"required": 0
}, {
"mail_parser_label": "Total",
"label": "Total",
"type": "text",
"arth": " ",
"id": 2,
"show": 1,
"app_side": 0,
"required": 0
}],
"other": [],
"body": []
},
"template_id": "NUEVO_PEDIDO",
"appCheck": true
}],
"taskDetails": {
"order_details":"Detalle\n Unidad\n Cantidad\n Total\n Triple Insomnio Especial S/37.90 1 S/37.90 Insomnio Especial \nS/212 S/23.12 *Tipo de papa:* - Papa Amarilla Tumbay S/0.00\n *Adicional :* - Quesp cheddar S/0.00\n *Agrega Bebida:* - Fanta 400 ml S/0.00\n *Salsas:* - Mayonesa S/0.00\n - Ketchup S/0.00\n - Golf S/0.00\n - Guacamole S/0.00\n - Ají S/0.00\n - Tártara S/0.00\n - Mayo-aji S/0.00\n   "
}
}
var items = opts.items;
var taskDetails = opts.taskDetails;
for (var p = 0; p < items.length; p++) {
var parameter = items[p];
if (parameter.mail_parser_label == "order_details") {
var str = taskDetails.order_details.toString().replace(/[ ]+/g, ' ');
var itemPatternFull = str.match(/[A-Za-z0-9 ]*S\/\d{1,}[.]*\d*\s+\d{1,}\s+S\/\d{1,}[.]*\d*/g);
var itemPattern = itemPatternFull ? itemPatternFull.toString().match(/S\/\d{1,}[.]*\d*\s+\d{1,}\s+S\/\d{1,}[.]*\d*/g) : [];
var details = itemPatternFull ? itemPatternFull.toString().replace(/S\/\d{1,}[.]*\d*\s+\d{1,}\s+S\/\d{1,}[.]*\d*/g, '').toString().split(',') : [];
var itemPatternLength = str.match(/S\/\d{1,}[.]*\d*\s+\d{1,}\s+S\/\d{1,}[.]*\d*/g).length;
var itemPattern = str.match(/S\/\d{1,}[.]*\d*\s+\d{1,}\s+S\/\d{1,}[.]*\d*/g);
var itemPatternArray = itemPattern.toString().replace(',', ' ').split(' ');
str = str.split(' ');
var count = 0;
if (itemPatternArray.length < str.length && details.length == itemPatternArray.length / 3) {
for (columnIndex = 0; columnIndex < itemPatternArray.length; columnIndex++) {
if (columnIndex % 3 == 0) {
parameter.data.body.push({
"val": details[count].trim(),
"id": count + columnIndex,
"head": "Dettalle"
});
count++;
}
parameter.data.body.push({
"val": itemPatternArray[columnIndex].replace(/S\//, ''),
"id": columnIndex + count,
"head": str[(columnIndex % 3) + 1] ? str[(columnIndex % 3) + 1].toString().replace('\n', '') : str[(columnIndex % 3) + 1]
});
}
}
} else {
parameter.data = taskDetails[parameter.mail_parser_label].toString().trim().replace(/[\s+\n]/g, ' ');
}
}
console.log("ITEMS", parameter.data.body)

Here is a regex to chop up your order_details and also extract the remainder at the end.
I used one rx to get header, items, and extras. Then another to parse the items using the g flag. You can validate even more, either in the regex, or parsing the match into a number, but you should get the point. The key is 2 phase parsing.
I put the results in an order object. You can simply map that to whatever you want; It was easier to show the regex and solution isolated from your other code.
var order_details = `Detalle\n Unidad\n Cantidad\n Total\n Triple Insomnio Especial S/37.90 1 S/37.90 Insomnio Especial \nS/23.12 1 S/23.12 Tipo de papa: - Papa Amarilla Tumbay S/0.00\n Adicional : - Quesp cheddar S/0.00\n Agrega Bebida: - Fanta 400 ml S/0.00\n Salsas: - Mayonesa S/0.00\n - Ketchup S/0.00\n - Golf S/0.00\n - Guacamole S/0.00\n - Ají S/0.00\n - Tártara S/0.00\n - Mayo-aji S/0.00\n " `
var order_details2 = `Detalle\n Unidad\n Cantidad\n Total\n Combo Cheese Burger para 2 S/39.90 1 S/39.90 Salsas primera: -\nGolf S/0.00\n Elige tu bebida: - Coca Cola 500ml S/0.00\n Elige tu bebida: - Coca Cola 500ml S/0.00\n Verduras primera : - Cebolla blanca S/0.00\n - Tomate S/0.00\n - Lechuga S/0.00\n Salsas segunda : - Golf S/0.00\n - Tártara S/0.00\n Verduras segunda : - Cebolla blanca S/0.00\n - Tomate S/0.00\n - Lechuga S/0.00\n Porción de papa : - Papa Regular S/0.00\n`
function parse(string) {
// header, items, and tipo
var rxItems = /Detalle\n Unidad\n Cantidad\n\ Total\n\s*([^:]+)(([^:]+:[\s\S]*)) /
// single item line
var rxItem = /s*(.*?)\s+(S\/.*?)\s+(\d+)\s+(S\/.*?)/g
var order = {
items: [],
other: null
}
var mParts = rxItems.exec(string)
var items = mParts[1]
order.other = mParts[2]
var mItem = rxItem.exec(items)
while (mItem) {
var detalle = mItem[1]
var unidad = mItem[2]
var cantidad = mItem[3]
var total = mItem[4]
let item = {
detalle,
unidad,
cantidad,
total
}
order.items.push(item)
mItem = rxItem.exec(items)
}
console.log(order)
}
parse(order_details)
parse(order_details2)

Related

JavaScript - Child elements get duplicated while using a for loop

The Problem:
I am willing to get a child element called optionName (you may have a look at the JSON array below to have a clearer idea on what's happening), which requires from me a nested for loop in order to get it. So far, I can get; however, the issue appears when I try to assign the value of that child element to a variable (line 5 in the code section), while I am doing the following additions += i.optionName which makes the value of i.optionName to be ordered (one after the other, similar to an array), the child elements get accumulated which makes the following appear:
Meal : Big Mac
Options :
Normal Ou Maxi ? : Maxi
Choix du boisson : Fanta Orange
Choix des frites : Frites steak house
Category : Menus
Qty : 1
Price : 49
Meal : Chicken McNuggets X6
Options :
//The first block is repeated again which is normal as I used additions +=**
Normal OR Big ? : Big
Choix du boisson : Fanta Orange
Choix des frites : Steak house
Normal OR Big ? : Normal
Choix du boisson : Sprite
Choix des frites : Steak house**
Category : Menus
Qty : 1
Price : 45
In short it's getting worse as much as the parent elements are more than that. You may say why I am doing that, the answer is because the below variable dishes it needs to be a string in this special case!
The current code:
let dishes = '';
let additions = '';
var msg = MessageContent.orderedDishes.forEach(function(element) {
for(var i of element.selectedAdditions){
additions += i.optionName +
' : '
+ i.Name + '\n';
}
dishes +=
'Meal : ' + element.dishName + '\n' +
'Options : \n' + additions + '\n' +
'Category : ' + element.categoryName + '\n' +
'Qty : ' + element.qty+ '\n' +
'Price : ' + element.price + '\n\n';
});
Here is the JSON array I am trying to iterate through:
[{
"objectId": "Kakao0MiRE",
"price": 49,
"dishName": "Big Mac",
"categoryName": "Menus",
"selectedAdditions": [{
"optionName": "Normal Ou Big ?",
"Name": "Big",
"Price": 5
}, {
"optionName": "Drink",
"Name": "Fanta Orange",
"Price": 0
}, {
"optionName": "Fries",
"Name": "Steak house",
"Price": 0
}],
"additionalPrice": 5,
"qty": 1
}, {
"objectId": "kOP90Ld8b9",
"price": 45,
"dishName": "Chicken McNuggets X6",
"categoryName": "Menus",
"selectedAdditions": [{
"optionName": "Normal Ou Maxi ?",
"Name": "Normal",
"Price": 0
}, {
"optionName": "Drink",
"Name": "Sprite",
"Price": 0
}, {
"optionName": "Fries",
"Name": "Frites steak house",
"Price": 0
}],
"additionalPrice": 0,
"qty": 1 }]
Your additions variable is defined declared outside of the call to forEach.
When forEach iterates, you concatenate values to the existing value of additions but never reset it to an empty string for each iteration. This is why your data builds up.
You can resolve this by setting the value of additions to an empty string at the beginning of your forEach callback, or by declaring it inside the forEach so that it starts with an empty array for each iteration. I'd suggest the latter:
let dishes = '';
var msg = MessageContent.orderedDishes.forEach(function(element) {
// declaring your variable here ensures that
// it is empty at the beginning of the iteration
// rather than accumulating over all of them:
let additions = '';
for(var i of element.selectedAdditions){
additions += i.optionName + ' : ' + i.Name + '\n';
}
dishes += 'Meal : ' + element.dishName + '\n'
+ 'Options : \n' + additions + '\n'
+ 'Category : ' + element.categoryName + '\n'
+ 'Qty : ' + element.qty+ '\n'
+ 'Price : ' + element.price + '\n\n';
});

Escape delphi strings to JavaScript function

I need to pass fields content from a table database to a JavaSricpt function in my web page.
I found an error when I have a backslash in the string :
{"DT_RowId":"4427","pront":"4427","nome":"JOHN DOE","conv":"PETROBRAS\ DISTR ( R)","cpf":"","email":""}
See:"PETROBRAS\"
In this case, I found that backslash was the cause of the problem.
I know I can solve this particular problem, but the table database I am using has many rows, and may be, can have others chars that can cause problems to JavaScript in my page
Is there a delphi function to escape all invalids chars(considering JavaScript) in a delphi string in order to pass to jasvascript function?
function EscapeDelphiStringToJS(s:string):string
begin
result:= "how could I do the escaping?"
end;
Remy, Here is the code I am using to create the Json. I am using XE8.
In order to return the data to my ajax function, I just convert the result function to string using: jso.tostring; But, this is not the problem.
function TContentClient.select_client(aParams: TStrings):
var so,jsoItem:TJsonObject;
jsa:TJsonArray;
jsp:TJSONPair;
ds:Tdataset;
.....
begin
TJsonObject;_recordsTotal:=IntToStr(ds.RecordCount);
jso:=TJsonObject.Create;
jso.AddPair('draw',TJsonNumber.Create(_draw));
jso.AddPair('recordsTotal',TJsonNumber.Create(_recordsTotal));
jso.AddPair('recordsFiltered',TJsonNumber.Create(_recordsTotal));
//create an json-array
jsa := TJsonArray.Create();
//add array to object
while not ds.eof do begin
//add items to the _first_ elemet of array
jsoItem := TJsonObject.Create();
//add object pairs
jsoItem.AddPair(TJsonPair.Create('DT_RowId',TJsonString.Create(ds.FieldByname('pront').AsString)));
jsoItem.AddPair(TJsonPair.Create('pront', TJsonString.Create(ds.FieldByname('pront').AsString)));
jsoItem.AddPair(TJsonPair.Create('nome', TJsonString.Create(ds.FieldByname('nome').AsString)));
jsoItem.AddPair(TJsonPair.Create('endereco', TJsonString.Create(ds.FieldByname('endereco').AsString)));
jsoItem.AddPair(TJsonPair.Create('bairro', TJsonString.Create(ds.FieldByname('bairro').AsString)));
jsoItem.AddPair(TJsonPair.Create('cidade', TJsonString.Create(ds.FieldByname('cidade').AsString)));
jsoItem.AddPair(TJsonPair.Create('estado', TJsonString.Create(ds.FieldByname('estado').AsString)));
jsoItem.AddPair(TJsonPair.Create('telefone', TJsonString.Create(ds.FieldByname('telres').AsString)));
jsoItem.AddPair(TJsonPair.Create('convenio', TJsonString.Create(ds.FieldByname('convenio').AsString)));
jsoItem.AddPair(TJsonPair.Create('cpf', TJsonString.Create(ds.FieldByname('cpf').AsString)));
jsoItem.AddPair(TJsonPair.Create('email', TJsonString.Create(ds.FieldByname('email').AsString)));
//put it into array
jsa.AddElement(jsoItem);
ds.Next;
end;
jsp := TJSONPair.Create('data', jsa);
jso.AddPair(jsp);
result:=jso;
end;
This is the result of the function:
{
"draw": 3,
"recordsTotal": 5303,
"recordsFiltered": 5303,
"data": [{
"DT_RowId": "2582",
"pront": "2582",
"nome": "XXXXX",
"endereco": "RUA TEODORO DA SILVA,333/103",
"bairro": "VILA ISABEL",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "3683*2690",
"convenio": "GOLDEN CROSS ( B)",
"cpf": "",
"email": ""
}, {
"DT_RowId": "2818",
"pront": "2818",
"nome": "YYYYY",
"endereco": "RUA PEREIRA NUNES , 395 AP 308",
"bairro": "VILA ISABEL",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "YYYYY",
"convenio": "UN",
"cpf": "216820707-00",
"email": ""
}, {
"DT_RowId": "1015",
"pront": "1015",
"nome": "YYYYYY",
"endereco": "rua francisca zieze, 192",
"bairro": "aboliçao",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "25945909",
"convenio": "UN",
"cpf": "71883592704",
"email": ""
}, {
"DT_RowId": "1701",
"pront": "1701",
"nome": "JJJJJJ",
"endereco": "AV 28 DE SETEMBRO 163 APT 704",
"bairro": "VILA ISABEL",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "2253-7625",
"convenio": "PETROBRAS DISTR\ ( R)",
"cpf": "",
"email": ""
}, {
"DT_RowId": "1076",
"pront": "1076",
"nome": "LLLLLLLL",
"endereco": "RUA ARISTIDES ,241/304",
"bairro": "MEIER",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "2501*6600",
"convenio": "CORREIOS",
"cpf": "",
"email": ""
}, {
"DT_RowId": "5959",
"pront": "5959",
"nome": "ZULEICA IIIII",
"endereco": "rua dos araujos 11a, bl 02 ap 301",
"bairro": "tijuca",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "2254-5682",
"convenio": "AMIL",
"cpf": "53150457734",
"email": ""
}, {
"DT_RowId": "5894",
"pront": "5894",
"nome": "ZULEICA AAAAA",
"endereco": "RUA PROF GABIZO,332/102",
"bairro": "TIJUCA",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "2568*9654",
"convenio": "UNIMED (SCOFANO)",
"cpf": "54016843715",
"email": ""
}, {
"DT_RowId": "4034",
"pront": "4034",
"nome": "ZILENE KAKAKA",
"endereco": "RUA AFONSO FERREIRA ,162",
"bairro": "ENGENHO DE DENTRO",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "2597*2352",
"convenio": "CORREIOS",
"cpf": "",
"email": ""
}, {
"DT_RowId": "5126",
"pront": "5126",
"nome": "ZILDA MAMAMA",
"endereco": "AV DOM HELDER CAMARA 1201",
"bairro": "BENFICA",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "7646-0691",
"convenio": "BRADESCO (B)",
"cpf": "",
"email": ""
}, {
"DT_RowId": "4497",
"pront": "4497",
"nome": "ZILDA LALALA",
"endereco": "RUA SABARRETO , 13 CASA",
"bairro": "FONSECA - NITEROI",
"cidade": "RIO DE JANEIRO",
"estado": "RJ",
"telefone": "2721-6646",
"convenio": "UNIMED (SCOFANO)",
"cpf": "",
"email": ""
}]
}
from svn https://svn.code.sf.net/p/alcinoe/code/ (you can find inside the unicode string implementation also but i prefere to gave here the ansiString as reference)
{******************************************************************************************}
// https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals
function ALJavascriptEncode(const Src: AnsiString; const useNumericReference: boolean = True): AnsiString;
var i, l: integer;
Buf, P: PAnsiChar;
ch: Integer;
begin
Result := '';
L := Length(src);
if L = 0 then exit;
if useNumericReference then GetMem(Buf, L * 6) // to be on the *very* safe side
else GetMem(Buf, L * 2); // to be on the *very* safe side
try
P := Buf;
for i := low(Src) to high(Src) do begin
ch := Ord(src[i]);
case ch of
8: begin // Backspace
if useNumericReference then begin
ALStrMove('\u0008', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\b', P, 2);
Inc(P, 2);
end;
end;
9: begin // Tab
if useNumericReference then begin
ALStrMove('\u0009', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\t', P, 2);
Inc(P, 2);
end;
end;
10: begin // New line
if useNumericReference then begin
ALStrMove('\u000A', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\n', P, 2);
Inc(P, 2);
end;
end;
11: begin // Vertical tab
if useNumericReference then begin
ALStrMove('\u000B', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\v', P, 2);
Inc(P, 2);
end;
end;
12: begin // Form feed
if useNumericReference then begin
ALStrMove('\u000C', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\f', P, 2);
Inc(P, 2);
end;
end;
13: begin // Carriage return
if useNumericReference then begin
ALStrMove('\u000D', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\r', P, 2);
Inc(P, 2);
end;
end;
34: begin // Double quote
if useNumericReference then begin
ALStrMove('\u0022', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\"', P, 2);
Inc(P, 2);
end;
end;
38: begin // & ... we need to encode it because in javascript ' or & will be converted to ' and error unterminated string
ALStrMove('\u0026', P, 6);
Inc(P, 6);
end;
39: begin // Apostrophe or single quote
if useNumericReference then begin
ALStrMove('\u0027', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\''', P, 2);
Inc(P, 2);
end;
end;
60: begin // < ... mostly to hide all </script> tag inside javascript.
// http://www.wwco.com/~wls/blog/2007/04/25/using-script-in-a-javascript-literal/
ALStrMove('\u003C', P, 6);
Inc(P, 6);
end;
62: begin // > ... mostly to hide all HTML tag inside javascript.
ALStrMove('\u003E', P, 6);
Inc(P, 6);
end;
92: begin // Backslash character (\).
if useNumericReference then begin
ALStrMove('\u005C', P, 6);
Inc(P, 6);
end
else begin
ALStrMove('\\', P, 2);
Inc(P, 2);
end;
end;
else Begin
P^:= AnsiChar(ch);
Inc(P);
end;
end;
end;
SetString(Result, Buf, P - Buf);
finally
FreeMem(Buf);
end;
end;

Alerting data specifics inside array

I'm running into a javascript beginner's problem. I have this data stored in an array, and I'm trying to alert the data to see if it checks out.
I want to alert myself the average of the distance of all, not both planets even though both is all in this case, but I eventually want to have an array that keeps a lot more than just two. Right now, it just alerts the distance of the last record in the array list, which is weird. I thought it'd be an average for all.
Also, how do I program the least and highest numbers of the "Distance" property in the array, and then alert the "Host name" with it. So, if I have a button and I click on "Closest", the Host name of the lowest number in "Distance [pc]" will be alerted. I only need an example of the code for "Distance", so I'll know how to do the same for all other variables.
Thank you if you're willing to help out!
Btw, the list is JSON data. Maybe important to mention this.
// this array holds the json data, in this case stastics of exoplanets retrieved from nasa's website
var arr= [ {
"rowid": 684,
"Host name": "K2-15",
"Number of Planets in System": 1,
"Planet Mass or M*sin(i)[Jupiter mass]": null,
"Planet Radius [Jupiter radii]": 0.221,
"Planet Density [g": {
"cm**3]": null
},
"Distance [pc]": 437,
"Effective Temperature [K]": 5131,
"Date of Last Update": "7/16/2015"
},
{
"rowid": 687,
"Host name": "K2-17",
"Number of Planets in System": 1,
"Planet Mass or M*sin(i)[Jupiter mass]": null,
"Planet Radius [Jupiter radii]": 0.199,
"Planet Density [g": {
"cm**3]": null
},
"Distance [pc]": 134,
"Effective Temperature [K]": 4320,
"Date of Last Update": "7/16/2015"
}];
//every record is put in a variable
var rowid;
var hostName;
var numberOfPlanetsInSystem;
var planetMass;
var planetRadius;
var distance;
var effectiveTemperature;
for(var i=0;i<arr.length;i++){
rowid= arr[i]["rowid"];
hostName= arr[i]["Host name"];
numberOfPlanetsInSystem= arr[i]["Number of Planets in System"];
planetMass= arr[i]["Planet Mass or M*sin(i)[Jupiter mass]"];
planetRadius= arr[i]["Planet Radius [Jupiter radii]"];
distance= arr[i]["Distance [pc]"];
effectiveTemperature= arr[i]["Effective Temperature [K]"];
};
//alert to test it out
alert(distance);
let totalDistance = maxDistance = 0;
let minDistance = arr[0]["Distance [pc]"];
let closestHost = farthestHost = "";
for(let i = 0; i < arr.length; i ++) {
totalDistance += arr[i]["Distance [pc]"]
if (arr[i]["Distance [pc]"] < minDistance) {
minDistance = arr[i]["Distance [pc]"];
closestHost = arr[i]["Host name"];
}
if (arr[i]["Distance [pc]"] > maxDistance) {
maxDistance = arr[i]["Distance [pc]"];
farthestHost = arr[i]["Host name"];
}
}
let meanDistance = totalDistance/arr.length;
In your cycle you are always overwrite your variable distance, not adding them.
Use distance += arr[i]["Distance [pc]"]
+= measn distance = distance + arr[i]["Distance [pc]"]
EDIT
Here is a working jsFiddle
You need to init var distance = 0;
var distance = 0; //Important!
var arr = [{
"rowid": 684,
"Host name": "K2-15",
"Number of Planets in System": 1,
"Planet Mass or M*sin(i)[Jupiter mass]": null,
"Planet Radius [Jupiter radii]": 0.221,
"Planet Density [g": {
"cm**3]": null
},
"Distance [pc]": 437,
"Effective Temperature [K]": 5131,
"Date of Last Update": "7/16/2015"
},
{
"rowid": 687,
"Host name": "K2-17",
"Number of Planets in System": 1,
"Planet Mass or M*sin(i)[Jupiter mass]": null,
"Planet Radius [Jupiter radii]": 0.199,
"Planet Density [g": {
"cm**3]": null
},
"Distance [pc]": 134,
"Effective Temperature [K]": 4320,
"Date of Last Update": "7/16/2015"
}];
for (var i = 0; i < arr.length; i++) {
distance += arr[i]["Distance [pc]"];
};
alert('Total distance: ' + distance + "\n" + 'Number of planets: ' + arr.length + "\n" + 'Average: ' + distance / arr.length);

Javascript remove leading and trailing spaces from multiline string and replace the rest of whitespace chunks with commas

How can I convert this text
data=`ID ra dec V VR MJD
100 30.1 +15 7.00 -10 2450000.1234
200 30.2 +16 12.226 -5.124 2450000.2345
300 30.3 +17 13.022 12.777 2450000.3456
400 30.4 +18 14.880 13.666 2450000.6789
500 30.5 +19 12.892 -1.835 2450001
600 30.6 +20 17.587 15.340 2450002.123
700 30.7 +21 13.984 13.903 2450000.123456
800 30.8 +22 20.00 10.000 2450003.0 `
i.e an imported text with multiple lines and columns separated by spaces and tabs, into this
ID,ra,dec,V,VR,MJD
100,30.1,+15,7.00,-10,2450000.1234
200,30.2,+16,12.226,-5.124,2450000.2345
300,30.3,+17,13.022,12.777,2450000.3456
400,30.4,+18,14.880,13.666,2450000.6789
500,30.5,+19,12.892,-1.835,2450001
600,30.6,+20,17.587,15.340,2450002.123
700,30.7,+21,13.984,13.903,2450000.123456
800,30.8,+22,20.00,10.000,2450003.0
Unfortunately,
this regex data=data.replace(/^\s+|\s+$/g,'').replace(/[\t \r]+/g,','); only works with the first line,
this one data.replace(/[^\S\r\n]+$/gm, "").replace(/[\t \r]+/g,',');
is ok, but only for for for traling.
Extra: How can I transform it to a json which separate the two blocks into two datasets such as [[{id:..., ra:...},{},{}],[{id:..., ra:...},{},{}]]
The string conversion might be easier with split/join and trim:
data
.split(/\r?\n/)
.map(row => row.trim().split(/\s+/).join(','))
.join('\n')
The extra credit is a little more involved. :)
const rows = data.split(/\r?\n/).map(row => row.trim().split(/\s+/).join(','));
const keys = rows.shift().split(',');
const chunks = rows.join("\n").split(/\n{2,}/);
const output = chunks .map(chunk => chunk.split("\n").map(
row => row.split(',').reduce((obj, v, i) => {
obj[keys[i]] = v;
return obj;
}, {})
));
You're nearly there. You want the multiline flag on the first replace,
but don't replace \n, so don't use \s. Use [ \t] instead:
var data = 'ID ra dec V VR MJD\n' +
' 100 30.1 +15 7.00 -10 2450000.1234\n' +
'200 30.2 +16 12.226 -5.124 2450000.2345\n' +
' 300 30.3 +17 13.022 12.777 2450000.3456\n' +
'\n' +
'\n' +
'400 30.4 +18 14.880 13.666 2450000.6789\n' +
'500 30.5 +19 12.892 -1.835 2450001\n' +
' 600 30.6 +20 17.587 15.340 2450002.123\n' +
'700 30.7 +21 13.984 13.903 2450000.123456\n' +
'800 30.8 +22 20.00 10.000 2450003.0 \n'
var result = data.replace(/^[ \t]+|[ \t]+$/gm,'').replace(/[ \t]+/g,',')
console.log(result);
// First: the trimming part. Split on newlines, process
// each line by trimming it and replacing remaining white
// space with commas
var data = 'ID ra dec V VR MJD\n\
100 30.1 +15 7.00 -10 2450000.1234\n\
200 30.2 +16 12.226 -5.124 2450000.2345\n\
300 30.3 +17 13.022 12.777 2450000.3456\n\
\n\
\n\
400 30.4 +18 14.880 13.666 2450000.6789\n\
500 30.5 +19 12.892 -1.835 2450001\n\
600 30.6 +20 17.587 15.340 2450002.123\n\
700 30.7 +21 13.984 13.903 2450000.123456 \n\
800 30.8 +22 20.00 10.000 2450003.0 ';
data = data.split('\n');
var i = 0, l = data.length;
for ( ; i < l; i++)
data[i] = data[i].trim().replace(/\s+/g,',');
data = data.join('\n');
document.write('<h1>Formatted data string</h1><pre><code>'+data+'</code></pre>');
// Now to turn it into objects.
// We'll strip the first line because
// that'll be the list of column names:
var cols = data.replace(/^([^\n]+)\n/,'$1').split(','),
columnCount = cols.length;
data = data.replace(/^[^\n]+\n/,'');
// Now separate the 2 datasets
var datasets = data.split('\n\n\n');
document.write('<h1>First dataset</h1><pre><code>'+datasets[0]+'</code></pre>');
document.write('<h1>Second dataset</h1><pre><code>'+datasets[1]+'</code></pre>')
// Now we go through each line and
// place the values into objects which
// we'll push to an array
var processed = [];
i = 0;
l = datasets.length;
for ( ; i < l; i++){
processed[i] = [];
var lines = datasets[i].split('\n'),
lineCount = lines.length;
for (var j = 0; j < lineCount; j++){
var dataArray = lines [j].split(','),
obj = {};
for (var k = 0; k < columnCount; k++)
obj[cols[k]] = dataArray[k];
processed[i].push(obj);
}
}
var finalJSON = JSON.stringify(processed);
document.write('<h1>Final JSON</h1><pre><code>'+finalJSON+'</code></pre>');
So, since you know the exact format of each line, you can use capture groups on a per-line basis to extract the details. Try something like this:
/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/mg
Remember that \s matches all whitespace, while \S matches non-whitespace. You may need to tweak the capture groups to your liking, if necessary. Then, using the multiline and global flags, we are all set up to iterate over all the matches.
Here's the code:
// Your data, with the header removed, formatted as a string literal:
var data = "100 30.1 +15 7.00 -10 2450000.1234\n"+
"200 30.2 +16 12.226 -5.124 2450000.2345\n"+
" 300 30.3 +17 13.022 12.777 2450000.3456\n"+
"\n"+
"\n"+
"400 30.4 +18 14.880 13.666 2450000.6789\n"+
"500 30.5 +19 12.892 -1.835 2450001\n"+
" 600 30.6 +20 17.587 15.340 2450002.123\n"+
"700 30.7 +21 13.984 13.903 2450000.123456 \n"+
"800 30.8 +22 20.00 10.000 2450003.0";
// The pattern to grab the data:
var data_pattern = /^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/mg;
// Keep matching until we run out of lines that match...
var results = [];
var line_match;
while ((line_match = data_pattern.exec(data)) !== null){
// Parse the match into a json object and add it to the results.
results.push({
ID: line_match[1],
ra: line_match[2],
dec: line_match[3],
V: line_match[4],
VR: line_match[5],
MJD: line_match[6]
});
}
// Output the results.
console.log(JSON.stringify(results, null, 2));
And here's the results on the console:
[
{
"ID": "100",
"ra": "30.1",
"dec": "+15",
"V": "7.00",
"VR": "-10",
"MJD": "2450000.1234"
},
{
"ID": "200",
"ra": "30.2",
"dec": "+16",
"V": "12.226",
"VR": "-5.124",
"MJD": "2450000.2345"
},
{
"ID": "300",
"ra": "30.3",
"dec": "+17",
"V": "13.022",
"VR": "12.777",
"MJD": "2450000.3456"
},
{
"ID": "400",
"ra": "30.4",
"dec": "+18",
"V": "14.880",
"VR": "13.666",
"MJD": "2450000.6789"
},
{
"ID": "500",
"ra": "30.5",
"dec": "+19",
"V": "12.892",
"VR": "-1.835",
"MJD": "2450001"
},
{
"ID": "600",
"ra": "30.6",
"dec": "+20",
"V": "17.587",
"VR": "15.340",
"MJD": "2450002.123"
},
{
"ID": "700",
"ra": "30.7",
"dec": "+21",
"V": "13.984",
"VR": "13.903",
"MJD": "2450000.123456"
},
{
"ID": "800",
"ra": "30.8",
"dec": "+22",
"V": "20.00",
"VR": "10.000",
"MJD": "2450003.0"
}
]
I hope this helped.

javascript/node JSON parsing issue

Here is my example data:
http://api.setlist.fm/rest/0.1/setlist/4bf763f6.json
I'm just writing a node app that prints out the details of this page. What I'm concerned with are sets, set and song.
var sets = setlist.sets
res.write(JSON.stringify(sets)) // THIS SHOWS THE CORRECT DATA
var numSets = Object.keys(sets).length;
for(var i = 0; i < numSets; i++){
res.write("\nsets " + i);
var set = sets.set[i];
console.log(Object.getOwnPropertyNames(set))
var numSet = Object.keys(set).length;
res.write(JSON.stringify(set))
for(var j = 0; j < numSet; j++){
res.write("\nset " + (j+1) + " of " + numSet);
var song = set.song;
console.log(Object.getOwnPropertyNames(song))
numSong = Object.keys(song).length;
for(var k = 0; k < numSong; k++){
res.write("\n song " + j + "-" + k);
res.write("\n "+JSON.stringify(song[k]["#name"]));
}
}
}
what I get is:
set 1 of 1
song 0-0
"Lift Me Up"
song 0-1
"Hard to See"
song 0-2
"Never Enough"
song 0-3
"Got Your Six"
song 0-4
"Bad Company"
song 0-5
"Jekyll and Hyde"
song 0-6
"Drum Solo"
song 0-7
"Burn MF"
song 0-8
"Wrong Side of Heaven"
song 0-9
"Battle Born"
song 0-10
"Coming Down"
song 0-11
"Here to Die"
There are TWO song elements in set: (sorry no code block or it won't wrap)
{
"set": [{
"song": [{
"#name": "Lift Me Up"
}, {
"#name": "Hard to See"
}, {
"#name": "Never Enough"
}, {
"#name": "Got Your Six"
}, {
"#name": "Bad Company",
"cover": {
"#disambiguation": "British blues-rock supergroup",
"#mbid": "0053dbd9-bfbc-4e38-9f08-66a27d914c38",
"#name": "Bad Company",
"#sortName": "Bad Company",
"#tmid": "734487",
"url": "http://www.setlist.fm/setlists/bad-company-3bd6b8b0.html"
}
}, {
"#name": "Jekyll and Hyde"
}, {
"#name": "Drum Solo"
}, {
"#name": "Burn MF"
}, {
"#name": "Wrong Side of Heaven",
"info": "Acoustic"
}, {
"#name": "Battle Born",
"info": "Acoustic and Electric"
}, {
"#name": "Coming Down"
}, {
"#name": "Here to Die"
}]
}, {
"#encore": "1",
"song": [{
"#name": "Under and Over It"
}, {
"#name": "Burn It Down"
}, {
"#name": "The Bleeding"
}]
}]
}
In Swift I just make set a Dictionary and it works just fine. Javascript is not my forte. Why can't I get that second song element?
setlist.set is an array of two objects, one containing the "regular"(?) songs and the other containing the encore information.
It looks like you are mixing up loop variables with other objects/arrays and not iterating what you think you're iterating.
Here's a simplified version that should show what you're expecting:
// `sets` is an object containing (at least) `set` and `url` properties
var sets = setlist.sets;
// `set` is an array containing (in your example, two) objects
var set = sets.set;
for (var i = 0; i < set.length; ++i) {
console.log('Set %d/%d', i+1, set.length);
// `curSet` is an object containing a `song` property
var curSet = set[i];
// `songs` is an array of objects
var songs = curSet.song;
for (var j = 0; j < songs.length; ++j) {
// `song` is an object containing properties like `#name` and possibly others
var song = songs[j];
console.log(' - Song: %s', song['#name']);
}
}
The line
var numSets = Object.keys(sets).length;
Should be
var numSets = sets.set.length;
May I also suggest that you use a forEach loop rather than a for loop (a .map() would be even better). for loops are much more prone to bugs than the alternatives.

Categories

Resources