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.
Related
In Javascript, I have the following String:
"|John Doe|[user:001] created article |Article Name|[article:001]"
How do I make the code parse it to "John Doe created article Article Name"?
My Solved Problem Code
based on suggestions from Agi Hammerthief
var splitedStr = str.split("|");
var filtered = splitedStr.filter(function (el) {
return el !== "";
});
$.each(filtered, function( index, value ) {
var mySubString = value.substr(
value.lastIndexOf("[") + 1,
value.lastIndexOf("]") - 1
);
if (mySubString.trim()) {
filtered[index] = value.replace('['+mySubString+']', '');
var infoLink = mySubString.split(":");
filtered[index - 1] = "<a href='/"+infoLink[0]+"/"+infoLink[1]+"'>" + filtered[index - 1] + "</a>";
}
});
console.log(filtered.join(""));
That line almost looks like a fragment from a Markdown document (although it doesn't use the same format for hyperlinks). If you're creating the String instead of getting it from an outside source, you might want to change the format and use a markdown processor.
Alternately:
Split the String on "|" (pipe)
Filter out empty Strings in the array
Use a loop to find the content between "[" and "]" (indexOf() and substring()) and make a link with text from the previous item in the array.
You can use regex and groups:
\|([\w ]*)\|\[([\w:]*)\]([\w ]*)\|([\w ]*)\|\[([\w:]*)\]
Group 1 is 'John Doe', 2 is 'user:001', 3 is ' created article ', 4 is 'Article Name', 5 is 'article:001'
Assume i have a string
var str = " 1, 'hello' "
I'm trying to give a function the above values found in str but as integer and string- not as one string-
for example myFunc(1,'hello')
how can i achieve that
i tried using eval(str),
but I'm getting invalid token ,
How can i solve this?
The following should work with any number of arguments.
function foo(num, str) {
console.log(num, str);
}
const input = "1, 'hel,lo'";
const args = JSON.parse('[' + input.replace(/'/g, '"') + ']');
foo(...args);
You've almost got the right idea with eval(str) however, that isn't the thing you actually want to evaluate. If you do use eval(str), it is the same as saying eval(" 1, 'hello' ")
However, what you really want to do is:
eval("func(1, 'hello world')).
To do this you can do:
eval(func.name + '(' + str.trim() + ')');
Here we have:
func.name: The name of the function to call. You can of course hard code this. (ie just write "func(" + ...)
str.trim(): The arguments you want to pass into the given function. Here I also used .trim() to remove any additional whitespace around the string.
Take a look at the snippet below. Here I have basically written out the above line of code, however, I have used some intermediate variables to help spell out how exactly this works:
function func(myNum, myStr) {
console.log(myNum*2, myStr);
}
let str = " 1, 'hello, world'";
// Build the components for the eval:
let fncName = func.name;
let args = str.trim();
let fncStr = fncName + '(' + args + ')';
eval(fncStr);
Alternatively, if you only wish to pass in two arguments you can use .split(',') on your string to split the string based on the comma character ,.
Using split on " 1, 'hello' " will give you an array such as this one a:
let a = [" 1", "'hello'"];
Then cast your string to an integer and remove the additional quotes around your string by using .replace(/'/g, ''); (replace all ' quotes with nothing ''):
let numb = +a[0].trim(); // Get the number (convert it to integer using +)
let str = a[1].trim().replace(/'/g, ''); // get the string remove whitespace and ' around it using trim() and replace()
Now you can call your function using these two variables:
func(numb, str);
function func(myNum, myStr) {
console.log('The number times 2 is:', myNum*2, "My string is:", myStr);
}
let arguments = " 1, 'hello' ";
let arr = arguments.split(',');
let numb = +arr[0].trim(); // Argument 1
let str = arr[1].trim().replace(/'/g, ''); // Argument 2
func(numb, str);
I have an array of objects which is a string.
[{
'version_name': '1.4',
'url': 'url'
},
{
'version_name': '1.3',
'url': 'url'
},
{
'version_name': '1.2',
'url': 'url'
},
{
'version_name': '1.1',
'url': 'url'
}]
I am using this code to remove all the space:
str = str.replace(/\s+/g, '');
Now, I want to convert it to proper array of objects. How do i do that?
I tried string.split() which kind of works but each array element becomes a string instead of an object.
If you control the source of the string, the best thing would be to modify the source so that it creates valid JSON (" instead of ' on property keys and strings).
If you can't change the source of it and have to deal with that string, you have a couple of options:
Replace the ' with " and use JSON.parse, since that text is valid JSON other than that it uses ' instead of " and it doesn't appear to use ' for anything else:
var result = JSON.parse(theText.replace(/'/g, '"'));
Live Example:
var theText = "[{'version_name':'1.1','url':'value'}, {'version_name':'1.2','url':'value'}, {'version_name':'1.32','url':'value'}, {'version_name':'1.4','url':'value'}]";
var result = JSON.parse(theText.replace(/'/g, '"'));
console.log(result);
Your other option, if you trust the source of that text, is to use eval, since the quoted text is valid JavaScript object initializer syntax.
// ONLY IF YOU CAN ABSOLUTELY TRUST THE SOURCE OF THAT TEXT
var result = eval(theText);
Live Example:
var theText = "[{'version_name':'1.1','url':'value'}, {'version_name':'1.2','url':'value'}, {'version_name':'1.32','url':'value'}, {'version_name':'1.4','url':'value'}]";
var result = eval(theText);
console.log(result);
A JSON string expects key and value to be wrapped in double quotes and not in single. But replacing every single quote can be incorrect as it can be a part of value. So you can pass string through series of regex to make it in correct format.
Sample:
var str = "[{'invalid_value': 'foo's','version_name': '1.4','url': 'url'} , {'version_name': '1.3','url': 'url'},{'version_name': '1.2','url': 'url'},{'version_name': '1.1','url': 'url' }]";
function parseObj(str) {
str = str.replace(/\'\s*:\s*\'/g, '":"');
str = str.replace(/\'\s*,\s*'/g, '","');
str = str.replace(/{\s*\'/g, '{"');
str = str.replace(/\'\s*}/g, '"\}');
return JSON.parse(str);
}
console.log(parseObj(str))
you can use json parse: const arr = JSON.parse(yourString.replace(/'/g, '"')))
I have a string and two arrays of tokens in the order they are placed in the string:
var str = `abc TOKEN_EXPRESSION TOKEN_OPERATOR textTOKEN_EXPRESSIONTOKEN_OPERATOR`;
var expressions = [
'z1',
'f3'
];
var operators = [
'+',
'OR'
];
In the end, I want to get one array containing expression and operator tokens alongside simple text in the order they appear in the string. So the result should look like that:
['abc ', 'z1', ' ', '+', ' text', 'f3', 'OR']
At the moment, my approach is to work with the string, search for either TOKEN_EXPRESSION or TOKEN_OPERATOR and cut the beginning of the string step by step. So it works like this now:
found remaining string
--------------------------
'abc' 'TOKEN_EXPRESSION TOKEN_OPERATOR textTOKEN_EXPRESSIONTOKEN_OPERATOR'
'z1' ' TOKEN_OPERATOR textTOKEN_EXPRESSIONTOKEN_OPERATOR'
' ' 'TOKEN_OPERATOR textTOKEN_EXPRESSIONTOKEN_OPERATOR'
'+' ' textTOKEN_EXPRESSIONTOKEN_OPERATOR'
But I feel there's gotta to be a better, easier to understand and more efficient way to do that. Any ideas?
It could be easier to use replace method and its groups' flags feature:
// Initialize two separate counters
var exc = 0, opc = 0;
// Replace each found group with corresponding value
result = str.replace(/TOKEN_(?:(EXPRESSION)|(OPERATOR))/g, function(match, p1, p2) {
return "$$" + (p1 ? expressions[exc++] : operators[opc++]) + "$$"
});
// Split on delimiters
console.log(result.split("$$").filter(String))
Output:
["abc ", "z1", " ", "+", " text ", "f3", "OR"]
May be you can do as follows;
var str = `abc TOKEN_EXPRESSION TOKEN_OPERATOR textTOKEN_EXPRESSIONTOKEN_OPERATOR`,
expressions = ['z1','f3'],
operators = ['+', 'OR'],
result = str.split(/TOKEN_(EXPRESSION|OPERATOR)/)
.reduce((p,c) => (c && (c === "EXPRESSION" ? p.push(expressions.shift())
: c === "OPERATOR" ? p.push(operators.shift())
: p.push(c)), p),[]);
console.log(result);
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