Parsing a templated string - javascript

I have a string like this
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");'
I wanted to parse this string to generate a json something like
[{id: 'a', map: 'b'},
{id: 'foo', map: 'bar'},
{id: 'alpha', map: 'beta'}]
I was wondering if regex is the best way to do this or if theres any utility lib I could leverage

Here's a regex that should work for your current case:
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");';
const res = str.split(";").map(e => {
const k = e.match(/map\("(.+?)"\)to\("(.+?)"\)/);
return k && k.length === 3 ? {id: k[1], map: k[2]} : null;
}).filter(e => e);
console.log(res);
The idea is to split on semicolons (a lookaround could be used to handle cases when semicolons are part of your desired key/value), then map these pairs into the desired object format based on a regex that parses the map("")to("") format. Finally, nulls are filtered out.

I'm pretty sure there is a nice regex solution which is shorter and faster, but since i'm bad at regex i solve those things like that:
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");'
const result = str.split(';').map(e => {
const parts = e.substring(3).split('to').map(item => item.replace(/\W/g, ''));
return {
id: parts[0],
map: parts[1]
};
})
console.log(result);

Related

How can I extract an array of substring via regex in nodes?

I have a string var whose value is (1,2)(3,4) and I'd like to extract an array [[1,2],[3,4]] from it. The solution I have is to use str.match but I haven't figured out how to extract the array.
I have tried:
> '(1,2)(3,4)'.match(/([\d]+),([\d])*/)
[ '3,2', '3', '2', index: 1, input: '(3,2)(4,5)', groups: undefined ]
The result is not what I want. So what should I do with the regex for that?
You need to use /(\d+),(\d+)/g or - to only get those inside parentheses - /\((\d+),(\d+)\)/g and get the results using RegExp#exec in a loop:
var s = '(1,2)(3,4)', m, results=[];
var rx = /(\d+),(\d+)/g;
while(m=rx.exec(s)) {
results.push([m[1], m[2]])
}
console.log(results);
Or, with matchAll if you target the latest JS environments:
const s = '(1,2)(3,4)', rx = /(\d+),(\d+)/g;
const results = [...s.matchAll(rx)];
console.log(Array.from(results, x => [x[1],x[2]]))
There's the other way around, without using RegExp, just in case:
const src = '(1,2)(3,4)',
result = src
.slice(1,-1)
.split(')(')
.map(s => s.split(','))
console.log(result)
.as-console-wrapper{min-height:100%;}

Java script key value pair to object

I am new to javascript. I have an array of data in the format:
Toronto, Ontario: 95
Markham, Ontario: 71
I want to convert it to an array of object:
Like this, to be consistent with other functions.
I tried:
reportData.fbcity = Object.keys(reportData.city).map((city) => {
return {
city: city,
value: reportData.city[city]
};
});
What I get is:
{city: "Markham, Ontario": "value": 71}
Based on your updated question, I take it that you have this:
const start = ["Toronto, Ontario: 95", "Markham, Ontario: 71"];
and you want this:
result = [
{"Toronto, Ontario": 95},
{"Markham, Ontario": 71}
];
To do that, you need to split the number at the end of the string off, and then build objects with the two parts of the string. If you know there's only ever one :, then:
const result = start.map(str => {
const [city, number] = str.split(":");
return {
[city]: +number
};
});
Live Example:
const start = ["Toronto, Ontario: 95", "Markham, Ontario: 71"];
const result = start.map(str => {
const [city, number] = str.split(":");
return {
[city]: +number
};
});
console.log(result);
That uses destructuring to capture the two parts from split, then a computed property name to create a property with the city name, and + to coerce the number to number from string. (That's just one of your number-to-string options, see this answer for more options.)
reportData.fbcity = Object.keys(reportData.city).map((city) => {
return {
[city]: reportData.city[city]
};
})
You can use map and split
split with : and than build a object
+ is used to convert string to number
let data = ["Toronto, Ontario: 95", "Markham, Ontario: 71"];
let op = data.map(val=>{
let [key,value] = val.split(':')
return {[key]: +value}
})
console.log(op)

how to put a regex test inside a arr.find

I have an array like so:
const arr = [{id: "12f"},{id: "12F"},{id: "13"}]
const itemToBeFound = {id: "12f"}
I want to be able to find that item using something like RegExp(/12f/i).test(string)
So the point of using the regexp is to be case insensitive. I know I could use toLowerCase or toUpperCase, I was just wanting to know how to do it this way.
So arr.find(({id}) => id == regexp) something to that affect. I haven't been able to figure out how to achieve this yet.
You need to just test the property against the RegExp
const arr = [{
id: "12f"
}, {
id: "12F"
}, {
id: "13"
}];
var regexp = new RegExp(/12f/i);
console.log(arr.find(({id}) => /12f/i.test(id)))
console.log(arr.filter(({id}) => /12f/i.test(id)))
This one-liner does all the job, according to the current question setup:
const foundItems = arr.filter((item) => (/[itemToBeFound.id]/gi).test(item.id))
The pattern and flags params of RegExp can be leveraged conduct dynamic comparison like so:
// Loose Match.
const filter = (array, target) => {
const regex = new RegExp(target.id, 'i')
return array.filter(x => regex.test(x.id))
}
// Proof.
console.log('12f', filter([{id: "12f"},{id: "12F"},{id: "13"}], {id: "12f"}))
console.log('13', filter([{id: "12f"},{id: "12F"},{id: "13"}], {id: "13"}))

Converting an Array into object in Javascript

I want to know the best way to convert an array in Js to object.
This is the sample of what i want to do.
Input => ['abc', 'def'];
Output => { abc: true, def: true }
I have done it using the code below. But just wanted to know if
**function toObject(strings) {
var rv = {}
strings.forEach(string => {
rv[string] = true
})
return rv
}**
This function serves the purpose. But any experts out there with a best and efficient way possible.
Not sure what you mean by best and efficient way possible, since yours is alright according to me, this is a less versbose version
var output = strings.reduce( (a,c) => (a[c]=true, a), {})
Demo
var strings = ['abc', 'def'];
var output = strings.reduce( (a,c) => (a[c]=true, a), {});
console.log(output);
You could map single objects and assign it to the same object.
var array = ['abc', 'def'],
object = Object.assign(...array.map(key => ({ [key]: true })));
console.log(object);

How to create query parameters in Javascript?

Is there any way to create the query parameters for doing a GET request in JavaScript?
Just like in Python you have urllib.urlencode(), which takes in a dictionary (or list of two tuples) and creates a string like 'var1=value1&var2=value2'.
Here you go:
function encodeQueryData(data) {
const ret = [];
for (let d in data)
ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
return ret.join('&');
}
Usage:
const data = { 'first name': 'George', 'last name': 'Jetson', 'age': 110 };
const querystring = encodeQueryData(data);
URLSearchParams has increasing browser support.
const data = {
var1: 'value1',
var2: 'value2'
};
const searchParams = new URLSearchParams(data);
// searchParams.toString() === 'var1=value1&var2=value2'
Node.js offers the querystring module.
const querystring = require('querystring');
const data = {
var1: 'value1',
var2: 'value2'
};
const searchParams = querystring.stringify(data);
// searchParams === 'var1=value1&var2=value2'
functional
function encodeData(data) {
return Object.keys(data).map(function(key) {
return [key, data[key]].map(encodeURIComponent).join("=");
}).join("&");
}
Zabba has provided in a comment on the currently accepted answer a suggestion that to me is the best solution: use jQuery.param().
If I use jQuery.param() on the data in the original question, then the code is simply:
const params = jQuery.param({
var1: 'value',
var2: 'value'
});
The variable params will be
"var1=value&var2=value"
For more complicated examples, inputs and outputs, see the jQuery.param() documentation.
ES2017 (ES8)
Making use of Object.entries(), which returns an array of object's [key, value] pairs. For example, for {a: 1, b: 2} it would return [['a', 1], ['b', 2]]. It is not supported (and won't be) only by IE.
Code:
const buildURLQuery = obj =>
Object.entries(obj)
.map(pair => pair.map(encodeURIComponent).join('='))
.join('&');
Example:
buildURLQuery({name: 'John', gender: 'male'});
Result:
"name=John&gender=male"
We've just released arg.js, a project aimed at solving this problem once and for all. It's traditionally been so difficult but now you can do:
var querystring = Arg.url({name: "Mat", state: "CO"});
And reading works:
var name = Arg("name");
or getting the whole lot:
var params = Arg.all();
and if you care about the difference between ?query=true and #hash=true then you can use the Arg.query() and Arg.hash() methods.
This should do the job:
const createQueryParams = params =>
Object.keys(params)
.map(k => `${k}=${encodeURI(params[k])}`)
.join('&');
Example:
const params = { name : 'John', postcode: 'W1 2DL'}
const queryParams = createQueryParams(params)
Result:
name=John&postcode=W1%202DL
If you are using Prototype there is Form.serialize
If you are using jQuery there is Ajax/serialize
I do not know of any independent functions to accomplish this, though, but a google search for it turned up some promising options if you aren't currently using a library. If you're not, though, you really should because they are heaven.
The built-in URL class provides a convenient interface for creating and parsing URLs.
There are no networking methods that require exactly a URL object, strings are good enough. So technically we don’t have to use URL. But sometimes it can be really helpful.
👇 Example
let url = new URL("https://google.com/search");
url.searchParams.set('var1', "value1");
url.searchParams.set('var2', "value2");
url.searchParams.set('var3', "value3");
url.searchParams.set('var4', "value4 has spaces");
console.log(url)
A little modification to typescript:
public encodeData(data: any): string {
return Object.keys(data).map((key) => {
return [key, data[key]].map(encodeURIComponent).join("=");
}).join("&");
}
Just like to revisit this almost 10 year old question. In this era of off-the-shelf programming, your best bet is to set your project up using a dependency manager (npm). There is an entire cottage industry of libraries out there that encode query strings and take care of all the edge cases. This is one of the more popular ones -
https://www.npmjs.com/package/query-string
Here is an example:
let my_url = new URL("https://stackoverflow.com")
my_url.pathname = "/questions"
const parameters = {
title: "just",
body: 'test'
}
Object.entries(parameters).forEach(([name, value]) => my_url.searchParams.set(name, value))
console.log(my_url.href)
I have improved the function of shog9`s to handle array values
function encodeQueryData(data) {
const ret = [];
for (let d in data) {
if (typeof data[d] === 'object' || typeof data[d] === 'array') {
for (let arrD in data[d]) {
ret.push(`${encodeURIComponent(d)}[]=${encodeURIComponent(data[d][arrD])}`)
}
} else if (typeof data[d] === 'null' || typeof data[d] === 'undefined') {
ret.push(encodeURIComponent(d))
} else {
ret.push(`${encodeURIComponent(d)}=${encodeURIComponent(data[d])}`)
}
}
return ret.join('&');
}
Example
let data = {
user: 'Mark'
fruits: ['apple', 'banana']
}
encodeQueryData(data) // user=Mark&fruits[]=apple&fruits[]=banana
By using queryencoder, you can have some nice-to-have options, such custom date formatters, nested objects and decide if a val: true will be just value or value=true.
const { encode } = require('queryencoder');
const object = {
date: new Date('1999-04-23')
};
// The result is 'date=1999-04-23'
const queryUrl = encode(object, {
dateParser: date => date.toISOString().slice(0, 10)
});
const base = "https://www.facebook.com"
const path = '/v15.0/dialog/oauth'
const params = new URLSearchParams({
client_id: clientID,
redirect_uri: redirectUri,
state: randomState,
})
const url = new URL(`${path}?${params.toString()}`, base)
Here's an example to create query parameters and build URL from base using only JavaScript built-in constructor.
This is part of Facebook Login implementation in manual approach.
According to URLSearchParams doc's example, there's a line
const new_url = new URL(`${url.origin}${url.pathname}?${new_params}`);
and I've followed that practice.
This is by far the most standardized way to build URL I believe.
I was a bit surprised that JavaScript doesn't supports query or fragment arguments in thier URL constructor still in 2023, despite It's definately worth having that.
This thread points to some code for escaping URLs in php. There's escape() and unescape() which will do most of the work, but the you need add a couple extra things.
function urlencode(str) {
str = escape(str);
str = str.replace('+', '%2B');
str = str.replace('%20', '+');
str = str.replace('*', '%2A');
str = str.replace('/', '%2F');
str = str.replace('#', '%40');
return str;
}
function urldecode(str) {
str = str.replace('+', ' ');
str = unescape(str);
return str;
}

Categories