Get array of elements from a string and look up values - javascript

I have a calculation string from a database like:
var calc = "{a}+{b}==2"
and I want to pull all the elements with "{}" so that I can look up their values from a database. What's the fastest way of doing this, so I end up with an ordered array that I can look up, and replace the values back in the string.
I've considered:
- For loop, looking for { then finding the next }
- Split with a map
- IndexOf

Using regex
var exp = /{([^}]+)}/g ,index;
while(index = exp.exec("{a}+{b}==2")) {
console.log(index[1]);
}
.
Demo

Not sure if it's the "fastest" way, but you should consider using a regex.
Something like:
var calc = "{a}+{b}==2";
var re = /{([^}]+)}/g;
var res;
var result = [];
while (res = re.exec(calc))
{
result.push(res[1]);
}
console.log(result);
Your regex may need to be refined based on the actual definition of the {} expressions (based on allowed characters, quoting, etc.).
Once you have received the values back, you can then use replace to replace the values.
var values = {a: 1, b: 3};
var replaced = calc.replace(re,function(match,name) { return values[name]; });
console.log(replaced);
NB: be very careful if you plan to then send this to eval or the like.

Regex comes to the mind first but one other way of implementing this job in O(n) time could be;
function getDatas(s){
var dataOn = false;
return Array.prototype.reduce.call(s,(d,c) => dataOn ? c !== "}" ? (d[d.length-1] += c,d)
: (dataOn = false, d)
: c === "{" ? (dataOn = true, d.push(""),d)
: d, []);
}
var calc = "{a}+{b}+{colorSpace}==2",
result = getDatas(calc);
console.log(result);
So out of curiosity i have done some tests on JSBen and it seems that #jcaron's regex is indeed much efficient. You may extend those tests with any of your other ideas like indexOf or for loop.

Related

JavaScript RegExp - find all prefixes up to a certain character

I have a string which is composed of terms separated by slashes ('/'), for example:
ab/c/def
I want to find all the prefixes of this string up to an occurrence of a slash or end of string, i.e. for the above example I expect to get:
ab
ab/c
ab/c/def
I've tried a regex like this: /^(.*)[\/$]/, but it returns a single match - ab/c/ with the parenthesized result ab/c, accordingly.
EDIT :
I know this can be done quite easily using split, I am looking specifically for a solution using RegExp.
NO, you can't do that with a pure regex.
Why? Because you need substrings starting at one and the same location in the string, while regex matches non-overlapping chunks of text and then advances its index to search for another match.
OK, what about capturing groups? They are only helpful if you know how many /-separated chunks you have in the input string. You could then use
var s = 'ab/c/def'; // There are exact 3 parts
console.log(/^(([^\/]+)\/[^\/]+)\/[^\/]+$/.exec(s));
// => [ "ab/c/def", "ab/c", "ab" ]
However, it is unlikely you know that many details about your input string.
You may use the following code rather than a regex:
var s = 'ab/c/def';
var chunks = s.split('/');
var res = [];
for(var i=0;i<chunks.length;i++) {
res.length > 0 ? res.push(chunks.slice(0,i).join('/')+'/'+chunks[i]) : res.push(chunks[i]);
}
console.log(res);
First, you can split the string with /. Then, iterate through the elements and build the res array.
I do not think a regular expression is what you are after. A simple split and loop over the array can give you the result.
var str = "ab/c/def";
var result = str.split("/").reduce(function(a,s,i){
var last = a[i-1] ? a[i-1] + "/" : "";
a.push(last + s);
return a;
}, []);
console.log(result);
or another way
var str = "ab/c/def",
result = [],
parts=str.split("/");
while(parts.length){
console.log(parts);
result.unshift(parts.join("/"));
parts.pop();
}
console.log(result);
Plenty of other ways to do it.
You can't do it with a RegEx in javascript but you can split parts and join them respectively together:
var array = "ab/c/def".split('/'), newArray = [], key = 0;
while (value = array[key++]) {
newArray.push(key == 1 ? value : newArray[newArray.length - 1] + "/" + value)
}
console.log(newArray);
May be like this
var str = "ab/c/def",
result = str.match(/.+?(?=\/|$)/g)
.map((e,i,a) => a[i-1] ? a[i] = a[i-1] + e : e);
console.log(result);
Couldn't you just split the string on the separator character?
var result = 'ab/c/def'.split(/\//g);

regex to find specific strings in javascript

disclaimer - absolutely new to regexes....
I have a string like this:
subject=something||x-access-token=something
For this I need to extract two values. Subject and x-access-token.
As a starting point, I wanted to collect two strings: subject= and x-access-token=. For this here is what I did:
/[a-z,-]+=/g.exec(mystring)
It returns only one element subject=. I expected both of them. Where i am doing wrong?
The g modifier does not affect exec, because exec only returns the first match by specification. What you want is the match method:
mystring.match(/[a-z,-]+=/g)
No regex necessary. Write a tiny parser, it's easy.
function parseValues(str) {
var result = {};
str.split("||").forEach(function (item) {
var parts = item.split("=");
result[ parts[0] /* key */ ] = parts[1]; /* value */
});
return result;
}
usage
var obj = parseValues("subject=something||x-access-token=something-else");
// -> {subject: "something", x-access-token: "something-else"}
var subj = obj.subject;
// -> "something"
var token = obj["x-access-token"];
// -> "something-else"
Additional complications my arise when there is an escaping schema involved that allows you to have || inside a value, or when a value can contain an =.
You will hit these complications with regex approach as well, but with a parser-based approach they will be much easier to solve.
You have to execute exec twice to get 2 extracted strings.
According to MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec
If your regular expression uses the "g" flag, you can use the exec() method multiple times to find successive matches in the same string.
Usually, people extract all strings matching the pattern one by one with a while loop. Please execute following code in browser console to see how it works.
var regex = /[a-z,-]+=/g;
var string = "subject=something||x-access-token=something";
while(matched = regex.exec(string)) console.log(matched);
You can convert the string into a valid JSON string, then parse it to retrieve an object containing the expected data.
var str = 'subject=something||x-access-token=something';
var obj = JSON.parse('{"' + str.replace(/=/g, '":"').replace(/\|\|/g, '","') + '"}');
console.log(obj);
I don't think you need regexp here, just use the javascript builtin function "split".
var s = "subject=something1||x-access-token=something2";
var r = s.split('||'); // r now is an array: ["subject=something1", "x-access-token=something2"]
var i;
for(i=0; i<r.length; i++){
// for each array's item, split again
r[i] = r[i].split('=');
}
At the end you have a matrix like the following:
y x 0 1
0 subject something1
1 x-access-token something2
And you can access the elements using x and y:
"subject" == r[0][0]
"x-access-token" == r[1][0]
"something2" == r[1][1]
If you really want to do it with a pure regexp:
var input = 'subject=something1||x-access-token=something2'
var m = /subject=(.*)\|\|x-access-token=(.*)/.exec(input)
var subject = m[1]
var xAccessToken = m[2]
console.log(subject);
console.log(xAccessToken);
However, it would probably be cleaner to split it instead:
console.log('subject=something||x-access-token=something'
.split(/\|\|/)
.map(function(a) {
a = a.split(/=/);
return { key: a[0], val: a[1] }
}));

How to split a string by Node Js?

My array:
var str=['data1,data2 '];
I have used:
var arr = str.split(",");
But one error is showed. TypeError: Object data1,data2 has no method 'split'. How can I solve this problem.
My output will be:
arr= data1,data2
// or
arr[0]=data1;
arr[1]=data2;
How can I solve this problem ?
You should do this :
var arr = str.toString().split(",");
"TypeError: Object data1,data2 has no method 'split'" indicates the variable is not considered as a string. Therefore, you must typecast it.
update 08.10.2015 I have noticed someone think the above answer is a "dirty workaround" and surprisingly this comment is upvoted. In fact it is the exact opposite - using str[0].split(",") as 3 (!) other suggests is the real "dirty workaround". Why? Consider what would happen in these cases :
var str = [];
var str = ['data1,data2','data3,data4'];
var str = [someVariable];
str[0].split(",") will fail utterly as soon str holds an empty array, for some reason not is holding a String.prototype or will give an unsatisfactory result if str holds more than one string. Using str[0].split(",") blindly trusting that str always will hold 1 string exactly and never something else is bad practice. toString() is supported by numbers, arrays, objects, booleans, dates and even functions; str[0].split() has a huge potential of raising errors and stop further execution in the scope, and by that crashing the entire application.
If you really, really want to use str[0].split() then at least do some minimal type checking :
var arr;
if (typeof str[0] == 'string') {
arr = str[0].split(',')
} else {
arr = [];
}
If your starting point is a array with a string inside. This should work:
var arr = str[0].split(",");
Otherwise you should have a string as starting point for your code to work as you expected:
var str = 'data1,data2';
If you have more elements in the array you will need to iterate them with a for loop.
Edit to add other cases:
If you have several strings in that array, then you should be more carefull and do something like this:
var str = ['data1,data2 ', ' data3, data4 ']; // notice these strings have many spaces in different places
var longString = str.join(',');
var array = longString.split(',').map(s => s.trim()).filter(Boolean); // removing spaces from start and end of strings, and eventually removing empty positions
console.log(array);
As you said, str is an array (with one element). If you want to split the string contained in the array, you have to access the array first:
var arr = str[0].split(",");
let's say we have two date :
date1: 17/01/1989
date2: 20/02/2000
if we want to compare them just split the string and compare like this
var date1= date1.toString().split("/");
var date2= date2.toString().split("/");
var a = parseInt(date1[2] + date1[1] + date1[0]);
var b = parseInt(date2[2] + date2[1] + date2[0]);
if(a < b){
alert("date2 bigger than date1")}
}
else if(a > b){
alert("date1 bigger than date2")
}
else{
alert("date 1 and date2 are equals ");
}

How to remove the last matched regex pattern in javascript

I have a text which goes like this...
var string = '~a=123~b=234~c=345~b=456'
I need to extract the string such that it splits into
['~a=123~b=234~c=345','']
That is, I need to split the string with /b=.*/ pattern but it should match the last found pattern. How to achieve this using RegEx?
Note: The numbers present after the equal is randomly generated.
Edit:
The above one was just an example. I did not make the question clear I guess.
Generalized String being...
<word1>=<random_alphanumeric_word>~<word2>=<random_alphanumeric_word>..~..~..<word2>=<random_alphanumeric_word>
All have random length and all wordi are alphabets, the whole string length is not fixed. the only text known would be <word2>. Hence I needed RegEx for it and pattern being /<word2>=.*/
This doesn't sound like a job for regexen considering that you want to extract a specific piece. Instead, you can just use lastIndexOf to split the string in two:
var lio = str.lastIndexOf('b=');
var arr = [];
var arr[0] = str.substr(0, lio);
var arr[1] = str.substr(lio);
http://jsfiddle.net/NJn6j/
I don't think I'd personally use a regex for this type of problem, but you can extract the last option pair with a regex like this:
var str = '~a=123~b=234~c=345~b=456';
var matches = str.match(/^(.*)~([^=]+=[^=]+)$/);
// matches[1] = "~a=123~b=234~c=345"
// matches[2] = "b=456"
Demo: http://jsfiddle.net/jfriend00/SGMRC/
Assuming the format is (~, alphanumeric name, =, and numbers) repeated arbitrary number of times. The most important assumption here is that ~ appear once for each name-value pair, and it doesn't appear in the name.
You can remove the last token by a simple replacement:
str.replace(/(.*)~.*/, '$1')
This works by using the greedy property of * to force it to match the last ~ in the input.
This can also be achieved with lastIndexOf, since you only need to know the index of the last ~:
str.substring(0, (str.lastIndexOf('~') + 1 || str.length() + 1) - 1)
(Well, I don't know if the code above is good JS or not... I would rather write in a few lines. The above is just for showing one-liner solution).
A RegExp that will give a result that you may could use is:
string.match(/[a-z]*?=(.*?((?=~)|$))/gi);
// ["a=123", "b=234", "c=345", "b=456"]
But in your case the simplest solution is to split the string before extract the content:
var results = string.split('~'); // ["", "a=123", "b=234", "c=345", "b=456"]
Now will be easy to extract the key and result to add to an object:
var myObj = {};
results.forEach(function (item) {
if(item) {
var r = item.split('=');
if (!myObj[r[0]]) {
myObj[r[0]] = [r[1]];
} else {
myObj[r[0]].push(r[1]);
}
}
});
console.log(myObj);
Object:
a: ["123"]
b: ["234", "456"]
c: ["345"]
(?=.*(~b=[^~]*))\1
will get it done in one match, but if there are duplicate entries it will go to the first. Performance also isn't great and if you string.replace it will destroy all duplicates. It would pass your example, but against '~a=123~b=234~c=345~b=234' it would go to the first 'b=234'.
.*(~b=[^~]*)
will run a lot faster, but it requires another step because the match comes out in a group:
var re = /.*(~b=[^~]*)/.exec(string);
var result = re[1]; //~b=234
var array = string.split(re[1]);
This method will also have the with exact duplicates. Another option is:
var regex = /.*(~b=[^~]*)/g;
var re = regex.exec(string);
var result = re[1];
// if you want an array from either side of the string:
var array = [string.slice(0, regex.lastIndex - re[1].length - 1), string.slice(regex.lastIndex, string.length)];
This actually finds the exact location of the last match and removes it regex.lastIndex - re[1].length - 1 is my guess for the index to remove the ellipsis from the leading side, but I didn't test it so it might be off by 1.

javascript get string before a character

I have a string that and I am trying to extract the characters before the quote.
Example is extract the 14 from 14' - €14.99
I am using the follwing code to acheive this.
$menuItem.text().match(/[^']*/)[0]
My problem is that if the string is something like €0.88 I wish to get an empty string returned. However I get back the full string of €0.88.
What I am I doing wrong with the match?
This is the what you should use to split:
string.slice(0, string.indexOf("'"));
And then to handle your non existant value edge case:
function split(str) {
var i = str.indexOf("'");
if(i > 0)
return str.slice(0, i);
else
return "";
}
Demo on JsFiddle
Nobody seems to have presented what seems to me as the safest and most obvious option that covers each of the cases the OP asked about so I thought I'd offer this:
function getCharsBefore(str, chr) {
var index = str.indexOf(chr);
if (index != -1) {
return(str.substring(0, index));
}
return("");
}
try this
str.substring(0,str.indexOf("'"));
Here is an underscore mixin in coffescript
_.mixin
substrBefore : ->
[char, str] = arguments
return "" unless char?
fn = (s)-> s.substr(0,s.indexOf(char)+1)
return fn(str) if str?
fn
or if you prefer raw javascript : http://jsfiddle.net/snrobot/XsuQd/
You can use this to build a partial like:
var beforeQuote = _.substrBefore("'");
var hasQuote = beforeQuote("14' - €0.88"); // hasQuote = "14'"
var noQoute = beforeQuote("14 €0.88"); // noQuote = ""
Or just call it directly with your string
var beforeQuote = _.substrBefore("'", "14' - €0.88"); // beforeQuote = "14'"
I purposely chose to leave the search character in the results to match its complement mixin substrAfter (here is a demo: http://jsfiddle.net/snrobot/SEAZr/ ). The later mixin was written as a utility to parse url queries. In some cases I am just using location.search which returns a string with the leading ?.
I use "split":
let string = "one-two-three";
let um = string.split('-')[0];
let dois = string.split('-')[1];
let tres = string.split('-')[2];
document.write(tres) //three

Categories

Resources