Split key: value; pairs and exclude whitespace in matches - javascript

Let's say we've a string like this: ' key1 : value1 ; key2 : value2 value3 ' and we want to convert it into a javasript-object. We can match aything that is not a delimiter (:;) and capture these matches. Great, got this job done with a simple regular expression:
/([^:]+):?([^;]+);?/g
Problem with my current RegExp is, that it also include whitespace in the results. So the string above will result in something like this:
{
" key1 ": " value1 ",
" key2 ": " value2 value3 "
}
Not really what we want... So I've changed the RegExp to this:
/\s*([^:]+)\s*:?\s*([^;]+);?\s*/g
Arr, damn! The character-set [^:]+ matches anything that is not a colon (so also whitespace). What will result in something like this:
{
"key1 ": "value1 ",
"key2 ": "value2 value3 "
}
Any idea how we can capture only the keys / values, without including whitespace in the match. So that our result looks like this:
{
"key1": "value1",
"key2": "value2 value3"
}
By the way, this is how the full parsing-function looks like:
var parseAttributes = function (attribute) {
var REGEX_SPLIT_PAIRS = /;?([^:]+):?([^;]+);?/g;
var attributes = {};
var match;
while (match = REGEX_SPLIT_PAIRS.exec(pairs)) {
attributes[match[1]] = match[2];
}
return attributes;
};
Edit
Another way is doing it with splitting the attribute-string down into the pair-chunks. However, I think about a pure RegExp-solution, without trim:
var parseAttributes = function (attribute) {
var attributes = {};
attribute.split(';').forEach(function (pair) {
var pairs = pair.split(':');
if (pairs && pairs[0] && pairs[1]) {
attributes[pairs[0].trim()] = pairs[1].trim();
}
});
return attributes;
};

You could try the below regex to capture Key,Value pair separately
\s*(\S+)\s*:\s*([^;\s]*(?:\s*\w+))
DEMO

Can you guarantee that every entry will match the model " key : value ;", that every entry will have a ":" and a ";" delimiter? If so, this may work:
/\s*([^:]+?)\s*:\s*([^;]+?)\s*;/g

/\s*([^:]+)\s*:?\s*([^;]+);?\s*/g matches whitespace because the first match is greedy; to stop this just add a ? to the match.
I think that /\s*([^:]+?)\s*:?\s*([^;]+?)\s*;?\s*/g will do what you want.

I don't know if it will work but,
did you tried? /[a-z0-9]+/g

Related

Split a query string by "&" but some attribute has this "&" in the value

I try to split an query by "&", but some attribute also has this "&" in the value, may I know how to split it? For example:
const query = "attr1=value1&attr2=va & lu&e2&attr3=value3"
May I know how to split the query into an array without splitting the "va & lu&e2":
["attr1=value1", "attr2=va &%lu&e2", "attr3=value3"]
Thanks!
if you want to use these parameters on a query,
you should use encodeURIComponent() which will escape the string so it can be used as a value in a query.
const query = "attr1=" + value1 +
"&attr2=" + encodeURIComponent("va & lu&e2") +
"&attr3=" + value3
This will result in the following string:
"attr1=value1&attr2=va%20%26%20lu%26e2&attr3=value3"
So every '&' is encoded as '%26'
To split it you can now rely on the '&' sign:
const splitArray = query.split('&')
Although, I would use the encodeURIComponent() for every query parameter value. unless I know exactly which value I use and that it doesn't need escaping.
you could mark & differently when you are using it as a value: something like & for example and then create your own function for splitting.
like:
var acc = query[0];
var splitted = [];
for(let i = 1; i < query.length; i++) {
if(query[i] === '&' && query[i-1] !== '\') {
splitted.push(acc);
acc = "";
} else {
acc += query[i];
}
}
the code probably does not work, but hopes this can clarify something

Javascript Replace - Dynamic Value of Replacement

I have a template in a String and I want to replace a few of the placeholders with the values that I have in another string. For every placeholder that I replace, I also want to insert a break tag.
For eg if #ADDRESS2# is found in the template, I am using the following code to replace all its occurrences with value in string val.address2.
template_html = template_html.replace(/#ADDRESS2#/g, '<br />'+ val.address_2);
However there are scenarios when the string val.address2 is empty. In that case, I do not want to insert the break tag.
So I changed my code as follows
if( val.address_2.length > 0 ) {
template_html = template_html.replace(/#ADDRESS2#/g, '<br />'+ val.address_2);
} else {
template_html = template_html.replace(/#ADDRESS2#/g, '');
}
Is there a better way to write the above code as I have multiple Placeholders and for each Placeholder I have to write the code 2 times.
Use a regex replacement, to which you pass a function.
That function will get the replacement keys as input, and depending on if there's a replacement available, it will insert a empty string, or the replacement with a linebreak:
const template = "#foo# this bla bla #bar# but #baz# and stuff";
const replacements = {
foo: "test",
bar: "",
baz: "not empty"
};
const result = template.replace(/#([^#]+)#/g, (match, key) => {
// If there's a replacement for the key, return that replacement with a `<br />`. Otherwise, return a empty string.
return replacements[key] !== undefined
? "<br />" + replacements[key]
: "";
});
console.log("template:", template);
console.log("result:", result);
The only "gotcha" here is that the keys in the template string have to match the keys in your replacements object. That's not necessarily a bad thing, though, as it would make it slightly more intuitive if you'd look back at your code later on.
The regex may look intimidating, but it's really quite simple:
/#([^#]+)#/g
/: The start of the regex,
#: Literally the # character,
(: The start of a capturing group,
[^#]+ Any character that isn't a #. The + makes sure it matches as many as possible,
): The end of a capturing group,
#: Literally the # character,
/g: The end of the regex. g is the global flag, so it doesn't stop at the first result.
The capturing group basically tells the regex to group everything that's between the brackets. The groups are then returned individually.
Perhaps you meant this?
var val = {
"address_1": "Address 1",
"address_2": "",
"address_10": "Address 10",
}
var template_html = `My address is #ADDRESS1# delivery address is #ADDRESS2# and billing is #ADDRESS10#`
template_html = template_html.replace(/#ADDRESS(\d+)#/g, function(addr, num) {
var str = val["address_"+num]; return str?str+"<br/>":""
})
console.log(template_html)
If the same logic should be applied for multiple address fields, then you might benefit from a helper function:
template_html = template_html
.replace(/#CITY1#/g, PrefixBrIfNotEmpty(val.city_1))
.replace(/#CITY2#/g, PrefixBrIfNotEmpty(val.city_2))
.replace(/#CITY3#/g, PrefixBrIfNotEmpty(val.city_3))
.replace(/#ADDRESS1#/g, PrefixBrIfNotEmpty(val.address_1))
.replace(/#ADDRESS2#/g, PrefixBrIfNotEmpty(val.address_2))
.replace(/#ADDRESS3#/g, PrefixBrIfNotEmpty(val.address_3));
function PrefixBrIfNotEmpty(str) {
return str ? '<br />' + str : '';
}
You can use ternary operator (empty string evaluates to false)
template_html = template_html.replace(/#ADDRESS2#/g, val.address_2 ? '<br />'+ val.address_2 : '');
The simplest change is to use the ternary operator like this:
template_html = template_html.replace(/#ADDRESS2#/g, ( val.address_2.length > 0 ) ? '<br />'+ val.address_2 : '');
Still not particularly elegant but a bit shorter than the original.
You could take the value with a check.
template_html = template_html.replace(
/#ADDRESS2#/g,
val.address_2 && '<br />' + val.address_2
);
For more than one placeholder, you could take a dynamic approach and use same pattern for the search and replacements.
var val = { address_2: 'foo', country_1: 'bar' }
template_html = 'Address: #ADDRESS2#\nCountry: #COUNTRY1#\nnothing: #NOTHING#'
template_html = template_html.replace(
/#([^#]+)#/g,
(_, group) => {
var key = group.match(/^(\D+)(\d*)$/).slice(1).map(s => s.toLowerCase()).join('_');
return (val[key] || '') && '<br />' + val[key];
}
);
console.log(template_html);
For getting a smarter replacement, yoou could take the idea of same strings as tempate and for getting the data from an object. In this case, take the replacement value and take this as key for the object or take an empty string for unknown values.
var val = { ADDRESS2: 'foo', COUNTRY1: 'bar' }
template_html = 'Address: #ADDRESS2#\nCountry: #COUNTRY1#\nnothing: #NOTHING#'
template_html = template_html.replace(
/#([^#]+)#/g,
(_, key) => (val[key] || '') && '<br />' + val[key]
);
console.log(template_html);
You mean, something like this:
template_html = template_html.replace(/#ADDRESS(\d+)#/g, function(address, number) {
return val.hasOwnProperty('address_' + number)
? '<br />' + val['address_' + number]
: '';
};
You should use the val.hasOwnProperty just in case that val.['address_' + number] contains a value like 0, false, '', undefined, NaN or other falsy values.
It makes sure the value is displayed anyway, because an undefined isn't the same as not having the property at all.
It also avoids to get a value from the prototype, just in case.
This is based on mplungjan's answer.
If this is undesirable, and you only want to show strings, try this:
template_html = template_html.replace(/#ADDRESS(\d+)#/g, function(address, number) {
return val.hasOwnProperty('address_' + number)
&& val['address_' + number].length
&& (
(typeof val['address_' + number]) === 'string'
|| val['address_' + number] instanceof String
)
? '<br />' + val['address_' + number]
: '';
};
All of this checking ensures that it is a non-empty string (or String instance, because new String() returns a string object).
Checking if it is an instance of String prevents issues due to typeof new String() returning object.
Arrays and array-like objects have a length attributes (e.g.: jQuery instance, NodeList, {length: 1}, [0] and similars), but you dont want to show them as strings.

Javascript cut string by begin and end and store in array

I need a algorithm which is doing something like this:
var example = "Hello $$user$$ your real name is $$realname$$. Have a good day"
Output --> ["Hello ", "$$user$$", " your real name is ", "$$realname$$", ". Have a good day"]
Hence, split the part by a selected character and put them together in a string array. Can someone help me out?
I'm looking for a solution with JavaScript/jQuery
It seems you want to split by pattern $$...$$; You could use /(\$\$.*?\$\$)/; To keep the pattern in the result, you can make it a capture group, and also make it lazy (?) so that it will split with the shortest length pattern matched:
example.split(/(\$\$.*?\$\$)/)
#[ 'Hello ',
# '$$user$$',
# ' your real name is ',
# '$$realname$$',
# '. Have a good day' ]
Yes, this is possible with JavaScript itself... Slightly tricky, but yes.
var strings = [], tokens = [];
var str = "Hello $$user$$ your real name is $$realname$$. Have a good day".replace(/\$\$(.*?)\$\$/g, "\$\$TOKEN$1\$\$").split("$");
for (var i = 0; i < str.length; i++) {
if (str[i].indexOf("TOKEN") === 0) {
// This is a token.
tokens.push(str[i].replace("TOKEN", ""));
} else {
strings.push(str[i]);
}
}
str = str.map(function (v) {
if (v.indexOf("TOKEN") === 0)
return "$$" + v.replace("TOKEN", "") + "$$";
return v;
});
console.log(str);
console.log(strings);
console.log(tokens);
The above code will split everything into tokens. And on top of it, it also separates the strings and tokens out. The above one gives as per your requirement:
[
"Hello ",
"$$user$$",
" your real name is ",
"$$realname$$",
". Have a good day"
]
Kindly note, there's nothing like {value, value}, there's only [value, value].
String.split()
The split() method splits a String object into an array of strings by separating the string into substrings.
var example = "Hello $$user$$ your real name is $$realname$$. Have a good day";
var exSplit = example.split("$$");
var userIdx = exSplit.indexOf("user");
var nameIdx = exSplit.indexOf("realname");
document.querySelector(".user").innerHTML = exSplit[userIdx];
document.querySelector(".name").innerHTML = exSplit[nameIdx];
<div class="user"></div>
<div class="name"></div>
Though, if I may suggest, variables can handle this type of operation without all of the hassle.

Spliting values based on condition in JavaScript array

Look at the below code or this fiddle
var arr = ["[Dim1].[Mem1].&[1]",
"[Dim2].[Mem1].&[2]",
"[Dim1].[Mem1].&[5]",
"[Dim2].[Mem1].&[77]",
"[Dim2].[Mem1].[All].Child",
"[Dim3].[Mem1].&[1]"];
var res = _.chain(arr)
.invoke("split", ".&")
.groupBy(0)
.map(function (els) {
return "{ " + _.invoke(els, "join", ".&").join(", ") + " }";
})
.value();
console.log(res);
this produces following output:
[
"{ [Dim1].[Mem1].&[1], [Dim1].[Mem1].&[5] }",
"{ [Dim2].[Mem1].&[2], [Dim2].[Mem1].&[77] }",
"{ [Dim2].[Mem1].[All].Child }",
"{ [Dim3].[Mem1].&[1] }"
]
The above code is using lodash library. It looks at the array and splits the values by '.&' and then groups the data by the resultant array's zero'th index.
This code is working fine and its doing whats its suppose to do.
Now consider a scenario where the input array does not have '.&' in it. In that case I want to split the input by '.' and then group the values. Is it possible to achieve the desired result by modifying code above? Or is it possible to do conditional split based on the input value?
var arrTwo = ["[Dim1].[Mem1].&[1]",
"[Dim2].[Mem1].&[2]",
"[Dim1].[Mem1].&[5]",
"[Dim2].[Mem1].&[77]",
"[Measures].[M11]",
"[Dim2].[Mem1].[All].Child",
"[Dim3].[Mem1].&[1]"],
"[Measures].[M1]",
"[Measures].[M2]";
Expected output:
[
"{ [Dim1].[Mem1].&[1], [Dim1].[Mem1].&[5] }" ,
"{ [Dim2].[Mem1].&[2], [Dim2].[Mem1].&[77] }",
"{ [Dim2].[Mem1].[All].Child }",
"{ [Dim3].[Mem1].&[1] }",
"{[Measures].[M11], [Measures].[M1], [Measures].[M2]}"
]
I'd suggest a regular expression in the groupBy callback instead of split:
var res = _.chain(arrTwo)
.groupBy(function(x) {
return x.match(/.+?\.&|[^.]+\./)[0]
})
.map(function (x) {
return "{ " + x.join(", ") + " }";
})
.value();
This seems to produce the desired result: http://jsfiddle.net/aAy6L/2/
That regular expression first tries to match everything up to, and including, .&. If it fails (i.e. there's no .& in the string) it backtracks and tries to match "some non-dots and a dot". The found match is used as a groupBy key.

Javascript splitting string in to two parts number and text safely

I was wondering if there is a safe way (if the data is coming from users) to get the string and the number separated - for example "something-55", "something-124", "something-1291293"
I would want:
something and
55
something and
124
something and
1291293
I mean by a 'safe way' is to be certain I am getting only the number on the end.. if the data is coming from the users "something" could be anything some-thing-55 for example..
I'm looking for a robust way.
try this, working.
var string = 'something-456';
var array = string.split('-');
for (var i = 0;i<array.length;i++){
var number = parseFloat(array[i]);
if(!isNaN(number)){
var myNumber = number;
var mySomething = array[i - 1];
console.log('myNumber= ' + myNumber);
console.log('mySomething= ' + mySomething);
}
}
Can you try this?
var input='whatever-you-want-to-parse-324';
var sections=input.split(/[\w]+-/);
alert(sections[sections.length-1]);
You can use substr along with lastIndexOf:
var str = "something-somethingelse-55",
text = str.substr(0, str.lastIndexOf('-')),
number = str.substr(str.lastIndexOf('-') + 1);
console.log(text + " and " + number);
Fiddle Demo
All though it's a tad late, this would be the most restrictive solution:
var regex = /^([-\w])+?-(\d+)$/,
text = "foo-123",
match = test.match(regex);
You will get a match object back with the following values:
[ "foo-123", "foo", "123" ]
It's a very strict match so that " foo-123" and "foo-123 " would not match, and it requires the string to end in one or more digits.

Categories