Escape delphi strings to JavaScript function - javascript

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;

Related

no return from Javascript function

I wrote this script based on information I read here on Stack. It calls data from an API and is supposed to convert the directional degrees to cardinal. When I run it, I get no output. There is no error when I inspect the page. I found no syntax errors when I ran it through Fiddle.
I thought I could simply substitute a number (I tried 45) for num and get the script to run to no avail so I could use an expert eye. Thank you.
var settings = {
"url": "https://api.stormglass.io/v1/weather/point?lat=40.370181&lng=-73.934193&key=...",
"method": "GET",
"timeout": 0,
};
$.ajax(settings)
.fail(function(a,b,c) { console.log(a.responseJSON) })
.done(function(response) {
console.log(response);
variconwndr24 = function degToCompass(num) {
var num = response.hours[17].windDirection[1].value;;
while (num < 0) num += 360;
while (num >= 360) num -= 360;
val = Math.round((num - 11.25) / 22.5);
arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE",
"SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"
];
return arr[Math.abs(val)];
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
First off, try something like this instead:
var settings = {
"url": "https://api.stormglass.io/v1/weather/point?lat=40.370181&lng=-73.934193&key=xdvfd",
"method": "GET",
"timeout": 0,
};
$.ajax(settings).done(function(response) {
console.log(response);
var degrees = response.hours[17].windDirection[1].value;
variconwndr24 = degToCompass(degrees);
console.log(variconwndr24);
return variconwndr24;
});
function degToCompass(num) {
while (num < 0) num += 360;
while (num >= 360) num -= 360;
val = Math.round((num - 11.25) / 22.5);
arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE",
"SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"
];
console.log(arr[Math.abs(val)]);
return arr[Math.abs(val)];
}
In the way you did it, degToCompass never actually gets called, and the num argument becomes redundant because you immediately redefine it.
The main problem is in the callback function for done. You're defining a function degToCompass, but that function is never called. Additionally, you're re-defining a parameter for the function that you passed. No point in passing num as a parameter if you just overwrite it. Instead just pass response's desired value as the parameter. Also, for the sake of readability and maintenance, try breaking this up like this :
const arr = [
"N",
"NNE",
"NE",
"ENE",
"E",
"ESE",
"SE",
"SSE",
"S",
"SSW",
"SW",
"WSW",
"W",
"WNW",
"NW",
"NNW"
];
var settings =
{
"url": "https://api.stormglass.io/v1/weather/point?lat=40.370181&lng=-73.934193&key=...",
"method": "GET",
"timeout": 0,
};
function degToCompass(num)
{
while (num < 0)
{
num += 360;
}
while (num >= 360)
{
num -= 360;
}
val = Math.round((num - 11.25) / 22.5);
return arr[Math.abs(val)];
}
function faiureCallback(a, b, c)
{
console.log(a.responseJSON);
}
function doneCallback(response)
{
// Do some stuff
var num = response.hours[17].windDirection[1].value;;
return degToCompass(num)
}
$.ajax(settings)
.fail(faiureCallback)
.done(doneCallback);

how can i get json property which has multiple spaces within the name?

"technicalData": [
{
"Technologie": "Bluetooth Low Energy 4.0",
"Größe (L x B x H)": "34.4 x 32.5 x 13 mm",
"Gewicht": "018 kg",
"Software": "Für die Arbeit benötigt, aber nicht im Lieferumfang enthalten. Registrierung für kostenlose Software-Verwendung und Premium-Services unter: www.bosch-trackmytools.com",
"Batterie": "CR 2032",
"Batterie Lebensdauer": "3 J",
"IP Schutzklasse": "IP 67",
"Robustheit": "IK 04",
"Befestigung": "2-Komponenten-Klebstoff oder Kabelhalter GCA 30-9 Professional"
}
]
I need to get "Größe (L x B x H)" butcant because it has multiple spaces, ["naming it "] doesnt work
At first, you have to proper define your json dictionary as follow:
json_dict = {"technicalData": [
{
"Technologie": "Bluetooth Low Energy 4.0",
"Größe (L x B x H)": "34.4 x 32.5 x 13 mm",
"Gewicht": "018 kg",
"Software": "Für die Arbeit benötigt, aber nicht im Lieferumfang enthalten. Registrierung für kostenlose Software-Verwendung und Premium-Services unter: www.bosch-trackmytools.com",
"Batterie": "CR 2032",
"Batterie Lebensdauer": "3 J",
"IP Schutzklasse": "IP 67",
"Robustheit": "IK 04",
"Befestigung": "2-Komponenten-Klebstoff oder Kabelhalter GCA 30-9 Professional"
}
]
}
Afterwards, you can get the property with this print() statement. Caution, the dictionary of interest is inside an array!
print(json_dict['technicalData'][0]['Größe (L x B x H)'])
# 34.4 x 32.5 x 13 mm
Hi that shouldn't be a problem at all, don't forget that your json is inside an array, but I'm sure that if you do this, you will be fine.
technicalData[0]["Größe (L x B x H)"]
It should return "34.4 x 32.5 x 13mm"

Use Regex to fetch data

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)

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 error - NaN

i have been going at this code all afternoon and i cannot figure out why this error is occurring. here is the code:
var ancestry = [{
"name": "Carolus Haverbeke",
"sex": "m",
"born": 1832,
"died": 1905,
"father": "Carel Haverbeke",
"mother": "Maria van Brussel"
}];
function average(array) {
function plus(a, b) {
return a + b;
}
return array.reduce(plus) / array.length;
}
var byCentury = new Object();
for (var i = 0; i < ancestry.length; i++) {
var centName = Math.ceil(ancestry[i].died / 100);
if (centName in byCentury) {
byCentury[centName].push(ancestry[i].age = ancestry[i].died - ancestry[i].born);
} else {
byCentury[centName] = [centName];
}
}
for (var century in byCentury) {
// For some reason no value is returned
var ages = byCentury[century].map(function(person) {
return person.age;
});
console.log(century + ': ' + average(ages));
}
The output i get is:
16: NaN
17: NaN
18: NaN
19: NaN
20: NaN
21: NaN
While the desired output is:
16: 43.5
17: 51.2
18: 52.8
19: 54.8
20: 84.7
21: 94
here is the challenge it has a built in code sandbox: http://eloquentjavascript.net/code/#5.3
The line
byCentury[centName].push(ancestry[i].age = ancestry[i].died - ancestry[i].born);
isn't pushing ancestry[i] into your array - it's pushing the value of ancestry[i].age. So later on, where you have:
var ages = byCentury[century].map(function(person) {
return person.age;
});
person is actually a number, so person.age will be undefined.
The other problem you have at the moment is what happens when you come to a person in the ancestry array whose century of birth hasn't been stored in byCentury yet.
if (centName in byCentury) {
...
} else {
byCentury[centName] = [centName];
}
Instead of storing their age, you store the number representing that century. One way of fixing it would be to change that block to:
if (byCentury[centName] === undefined) {
byCentury[centName] = [];
}
byCentury[centName].push(ancestry[i].died - ancestry[i].born);
and simply logging century + ': ' + average(byCentury[centName]) in your loop at the end. Finally, add in some rounding to make your output match that of the exercise, and you'll have your final solution.

Categories

Resources