javascript - Break search query string into object - javascript

I am trying to build api query in client side by breaking the user input in search field into object.
Example,
Search query
arg1:"2 words" business corporate arg2:val2
Desired value
{
arg1: "2 words",
arg2: "val2",
extra: "business corporate"
}
I tried doing this.
var query = initquery.split(' ');
var obj = {};
for(var i=0; i<query.length; i++){
var s = query[i].split(':');
if(s.length == 2) {
initquery = initquery.replace(query[i], '');
obj[s[0]] = s[1];
}
}
obj.extra = initquery;
This does not handle string in quotes.

You may want to take a look at this:
addEventListener('load', function(){
var wtf = 'arg1:"2 words" business corporate arg2:val2 arg3:"fixedIt"';
function customObj(string){
var a = string.split(/\s+(?!\w+")/), x = [], o = {};
for(var i=0,s,k,l=a.length; i<l; i++){
s = a[i].split(/:/); k = s[0];
s[1] ? o[k] = s[1].replace(/"/g, '') : x.push(k);
}
o['extra'] = x.join(' ');
return o;
}
console.log(customObj(wtf));
});

Thanks to #Barmar for this helpful comment, I came up with this regex to catch the args (assuming they are followed by a single digit number and a colon):
var pattern = /((^|\s)arg\d:").*?(?=")"?|(\sarg\d:\w*)/g;
Extracting the rest of the query can be done through:
query.replace(pattern,"");
And then creating the final object should be straightforward. Still, given the complexities that could rise from sprinkling double quotes in the query string, you should consider writing a parser for your application.
UPDATE:
Updated the regex to match beginning of the string and only match arg after white space character.

Related

How to replace/remove some part of a string

I have a string in which i want to remove some part.
1) below is the string( Encrypted message)
##_/profiles/c3ed4acd-b3be-487e-81b4-a27643745d^^____User1__###^^^ says hello to ##_/profiles/d3ac3c5a-8a9f-4640-8563-127674d93e^^____User2__###^^^
I want to get below 2 things from this
a) A string
#User1 says to #User2
2) A json object like
{
"c3ed4acd-b3be-487e-81b4-a27643745d":"User1",
"d3ac3c5a-8a9f-4640-8563-127674d93e":"User2"
}
First I tried to get string and used below approach using regex
I have tried it by doing like this
var str = "##___/profiles/c3ed4acd-b3be-487e-81b4-a27643745d__^^____User1__###^^^ says to ##___/profiles/d3ac3c5a-8a9f-4640-8563-127674d93e__^^____User2__###^^^"
var rx = /(^##___|,###^^^)/; // start with ##___ and end with ###^^^
var expectedString = str.replace(/(^##___|,###^^^)/g, "");
console.log(expectedString);
But this is just replace first occurance of
There are some fundamental problems in your code
you have to escape the ^ character as \^
you don't even use your rx variable
pipe character | means or, not start with and end with
try this:
// a)
var str = "##___/profiles/c3ed4acd-b3be-487e-81b4-a27643745d__^^____User1__###^^^ says to ##___/profiles/d3ac3c5a-8a9f-4640-8563-127674d93e__^^____User2__###^^^"
var rx = /##___([^_]+)__\^\^____([^_]+)__###\^\^\^/g;
var expectedString = str.replace(rx, "#$2");
console.log(expectedString);
// b)
var list = {};
while ((m = rx.exec(str)) !== null) {
if (m.index === rx.lastIndex) {
rx.lastIndex++;
}
list[m[1]] = m[2];
}
console.log(list);

How can I dynamically use string.replace?

wordsArray = ['guy', 'like', 'sweet', 'potatoes']; //so on and so forth
string = "I am a **NOUN** and I **VERB** **ADJECTIVE** **NOUN**.";
DELIMITER = "**";
for (var i = 0; i < wordsArray.length; i++)
{
string.replace(DELIMITER, wordsArray[i]);
}
Hi, this is a simplified version of my code. I'm creating a mad lib, and the length of wordsArray will always be equal to the number of fill in the blanks. The problem with my current code is that in the for loop, it will replace every **. The thing is, I want to replace the entire thing, like **NOUN**, not just **. But since whatever is in between ** ** won't always be the same, string.replace() won't exactly work. Can Anyone suggest me an edit that could replace all the part of speeches but still eventually return string as a, well, block of proper text?
You can do it using string.match by catching all those **<STRINGS>** first:
var wordsArray = ['guy', 'like', 'sweet', 'potatoes'];
var string = "I am a **NOUN** and I **VERB-** **ADJECTIVE** **NOUN**.";
var DELIMITER = "**";
var newString = string; // copy the string
var stringArray = string.match(/(\*\*[A-Za-z-]+\*\*)/g); // array of all **<STRINGS>**
for (var i = 0; i < wordsArray.length; i++) {
newString = newString.replace(stringArray[i], wordsArray[i]);
}
console.log(newString);
You can bind your array to the replacer and call replace on your string once, I think it is much simpler:
"I am a **NOUN** and I **VERB** **ADJECTIVE** **NOUN**.".replace(/(\*\*\w+\*\*)/gi,(function(){
this._currentIndex = this._currentIndex || 0;
return this[this._currentIndex++];
}).bind(['guy', 'like', 'sweet', 'potatoes']));
//"I am a guy and I like sweet potatoes."
Using reduce:
const string = "I am a **NOUN** and I **VERB** **ADJECTIVE** **NOUN**.";
const newString = ['guy', 'like', 'sweet', 'potatoes'].reduce(
(theString, replacement) => theString.replace(/\*{2}\w+\*{2}/, replacement),
string
)

Regex doesn't seem to work properly in my code

What I am trying to do is turn, for example "{{John}}" into "John".
First I am parsing from a string:
var parametrar = content.match(/[{{]+[Aa-Åå]+[}}]/g);
Here regex works fine and it parses as it should. I need to parse the "{}" to find stuff in the string.
But then I'm trying to parse out the "{}" from each "parametrar":
for (var i = 0; i < parametrar.length; i++) {
parametrar = parametrar[i].replace(/[{}]/g, "");
}
When I alert "parametrar" all I get is one "a". I have no idea what I'm doing wrong here, seems it should work.
Try to add greedy matching to maque's answer with using question mark(?).
"{{John}}".replace(/\{\{(.*?)\}\}/g,"$1");
It extracts "John" properly from "{{John}} and Martin}}" input. Otherwise it matches to "John}} and Martin".
You can match the name with braces around and then just use the first capturing group (m[1]):
var re = /\{{2}([a-zA-ZÅå]+)\}{2}/g;
var str = '{{John}}';
if ((m = re.exec(str)) !== null) {
paramterar = m[1];
alert(paramterar);
}
If you have a larger string that contains multiple {{NAME}}s, you can use the code I suggested in my comment:
var re = /\{{2}([a-zA-ZÅå]+)\}{2}/g;
var str = 'My name is {{John}} and {{Vasya}}.';
var arr = [];
while ((m = re.exec(str)) !== null) {
paramterar = m[1];
arr.push(m[1]);
}
alert(arr);
alert(str.replace(/([a-zA-ZÅå])\}{2}/g,"$1").replace(/\{{2}(?=[a-zA-ZÅå])/g, ""))
I have also fixed the character class to only accept English letters + Å and å (revert if it is not the case, but note that [Aa-Åå] is not matching any upper case Englihs letters from B to Z, and matches characters like §.) Please check the ANSI table to see what range you need.
Just do it like that:
"{{John}}".replace(/\{\{(.*)\}\}/g,"$1");
So you are searching for string that have double '{' (these needs to be escaped), then there is something (.*) then again '}' and your output is first match of the block.
Try this:
var parametrar = content.replace(/\{\{([a-åA-Å]+)\}\}/g, "$1");
This gives you a "purified" string. If you want an array, than you can do this:
var parametrar = content.match(/\{\{[a-åA-Å]+\}\}/g);
for (var i = 0, len = parametrar.length; i < len; i++) {
parametrar = parametrar[i].replace(/\{\{([a-åA-Å]+)\}\}/g, "$1");
}

split string and leave the separators intact

I cannot find a good way to split a string using a separator string but leave the separator as the prefix of each element of the resulting array:
from
var s = 'blah0__blah1__blah2';
I need to get
['blah0', '__blah1', '__blah2']
the closest thing that I could get was
s.split(/(__)/);
which returns
['blah0', '__', 'blah1', '__', 'blah2']
but this I would need to traverse to merge the underscores.
Is there a better way?
EDIT:
here is my best effort so far:
'blah__blah1__blah2'.split(/(__[^_]+)/)
// => ["blah", "__blah1", "", "__blah2", ""]
still, there are empty strings in the output...
How about this:
var s = 'blah0__blah__blah'
var s_split = s.match(/(__)?(.(?!__))+./g)
console.log(s_split)
I'm pretty sure it's much more costly (time and memory wise) than simply reiterating and joining after a regular split.
If you replace __ with your separator it should work fine for most cases.
A two-step process.
var s = 'blah0__blah1__blah2';
var blahs = s.split('__');
var scoreBlahs = blahs.map(preScore);
alert(scoreBlahs);
function preScore(b) {
var x;
var result = x.concat('__',b);
return result;
}
'blah0__blah1__blah2'.match(/^[^_]+|_+[^_]+/g);
["blah0", "__blah1", "__blah2"]
Seems to give you what you want. Though It may vary, if your input isn't exactly as you show it.
Just prepend the seperator after you seperate the string
var value = "a,b,c";
var splitter = value.split(",");
for(var i = 0; i < splitter.length; i++) {
alert("," + splitter[i]);
}
Since you know the separator - just add it again later on:
var s = 'blah0__blah1__blah2';
var sep = '__';
var arr = s.split(sep);
for (var i = 1; i < arr.length; i++) {
arr[i] = sep + arr[i];
}
console.log(arr);
You could insert a secondary separator, and split on that, leaving the original intact.
var s = 'blah0__blah1__blah2';
s = s.replace('_', '_$');
s.split('$');

Is it possible to simulate string.match with a regexp.exec loop when the regexp matches the empty string?

It is common knowledge that the exec method from RegExps can get used to find all matches in a string. However, I just found out that if the regexp matches the empty string this loop can get stuck forever
var s = '1234'
var r = /()/g;
var m;
var i = 0;
while( (m = r.exec(s)) ){
console.log(i, m[0]);
if(++i >= 50){ console.log("infinite loop!"); break }
}
What is really weird though is that the plain string.match methods does not get stuck:
'1234'.match(/()/g) // Gives ["", "", "", "", "", ""]
I wonder how the match method is defined to work differently from the exec loop. So far the only way I found to avoid getting stuck like the match method does involves abusing the string.replace method, in a horrid hack:
var matches = [];
'1234'.replace(/()/g, function(m){ matches.push(m) });
So my question is:
How do the match and replace return a finite results when the regexp matches the empty string? Can I use the same technique to avoid getting stuck in the exec loop?
One (icky) solution is to make sure it's not in the same place as last time:
var s = '1234'
var r = /()/g;
var m;
var i = 0;
var lastPosition = -1;
while(m = r.exec(s)) {
if(m.index === lastPosition) {
r.lastIndex++;
continue;
}
lastPosition = m.index;
console.log(i, m[0]);
}

Categories