I need to rewrite a querysting using javascript.
First I check to see if the variable is present, if it is I want to replace it with a new search term. If it is not present then I just add the new variable
I'm able to get it to work with simple terms like hat, ufc hat
whitespaces are %20, so ufc hat is really ufc%20hat
I run into problem with terms like make-up, hat -baseball, coffee & tea, etc..
What is the proper regex for this?
Below is my code, which doesn't work.
var url = String(document.location).split('?');
querystring = url[1];
if(querystring.match(/gbn_keywords=/)!=null)
querystring=querystring.replace(/gbn_keywords=[a-zA-Z0-9%20.]+/,"gbn_keywords="+term);
else
querystring=querystring+"&gbn_keywords="+term;
No Regex needed. To get the query arguments, take everything after ?. Then, split the string by & to return each argument. Split again by = to get the arg name (right of =) and the value (left of =). Iterate through each argument, a rebuild the URL with each argument, excluding the one you don't want. You shouldn't run into problems here because ?, &, and - must be escaped if they are to be used in arguments. You also said you want to add the argument if it doesn't exist, so just set a variable to true, while you are iterating through each argument, if you find the argument. If you didn't append it to the end of the query string that you rebuilt.
location objects already have perfectly good properties like pathname, hostname etc. that give you the separate parts of a URL. Use the .search property instead of trying to hack the URL as a string (? may not only appear in that one place).
It's then a case of splitting on the & character (and maybe ; too if you want to be nice, as per HTML4 B2.2) and checking each parameter against the one you're looking for. For the general case this requires proper URL-decoding, as g%62n_keywords=... is a valid way of spelling the same parameter. On the way out naturally you will need to encode again, to stop & going on to the next parameter (as well as to include other invalid characters).
Here's a couple of utility functions you can use to cope with query string manipulation more easily. They convert between the ?... string as seen in location.search or link.search and a lookup Object mapping parameter names to arrays of values (since form-url-encoded queries can have multiple instances of the same parameter).
function queryToLookup(query) {
var lookup= {};
var params= query.slice(1).split(/[&;]/);
for (var i= 0; i<params.length; i++) {
var ix= params[i].indexOf('=');
if (ix!==-1) {
var name= decodeURIComponent(params[i].slice(0, ix));
var value= decodeURIComponent(params[i].slice(ix+1));
if (!(name in lookup))
lookup[name]= [];
lookup[name].push(value);
}
}
return lookup;
}
function lookupToQuery(lookup) {
var params= [];
for (var name in lookup)
for (var i= 0; i<lookup[name].length; i++)
params.push(encodeURIComponent(name)+'='+encodeURIComponent(lookup[name][i]));
return params.length===0? '' : '?'+params.join('&');
}
This makes the usage as simple as:
var lookup= queryToLookup(location.search);
lookup['gbn_keywords']= ['coffee & tea'];
var query= lookupToQuery(lookup);
& character is used to seperate key and value pairs in the querystring. So that you can match all the characters except for & by re-writing your code as follows:
querystring=querystring.replace(/gbn_keywords=[^&]+/,"gbn_keywords="+term);
[^&]+ matches one or more characters up to & or end of string. But if there may situations where the querystring data may look like ...?gbn_keywords= (no value) then a slight modification is needed to the above line:
querystring=querystring.replace(/gbn_keywords=[^&]*/,"gbn_keywords="+term);
Just change + to * so that the regex will match 0 or more characters. I think this is better.
Why don't you run a split on url[1] and than replace the value of the gbn_keywords in that new array?
And if you use a JavaScript Framework, there might be a handy function that does all that. In Prototype there is the function toQueryParams().
Related
I have a file called 'test.abcde.houses.csv' and I want to extract the substring 'abcde' which I will use in my next processor group to query the database.
Currently, I am using the updateAttribute Processor group to try to extract the substring.
This is the code I am using in the value section.
var userPattern = java.util.regex.Pattern.compile('(.+?)\.[0-9]{8}-[0-9]{7,9}\..+');
var userMatcher = userPattern.matcher(fileName);
var matchExists = userMatcher.matches();
var user;
var userRemove;
if (matchExists) {
user = userMatcher.group(1);
userRemove = user + ".";
}
else {
throw 'Unable to parse username from file metadata.';
}
Question:
Is this the right way to extract a substring from a flow file name in NIFI?
Am I using the right processor group?
Does this code work with Nifi?
You need to use NiFi Expression Language, a kind of NiFi's own scripting feature which provides the ability to reference attributes, compare them to other values, and manipulate their values. Please refer to this official documentation.
UpdateAttribute processor is used to update/derive new/delete attributes. So you need to use the Expression Language inside UpdateAttribute to manipulate attributes.
Example:
test.abcde.houses.csv - this is your filename and if you want to extract abcde string from filename then you can use getDelimitedField function (Expression Language string function) like below. If the expression did not evaluate, then user attribute will be having empty/null value.
Property: user (if already present then update/assign value, otherwise create new attribute)
Value: ${filename:getDelimitedField(2, '.')} (abcde is at second index/position in filename attribute value)
Expression Language has Boolean, Conditional, String Manipulation, etc. functions, so you can easily replicate your JS logic into UpdateAttribute to derive desired attribute value.
I'm trying to create a regex pattern to match "faux" html tags for a small application i am building.
I have created the regex to capture found matches within {tag}brackets{/tag} and output them into an array of objects like so:
{
{key : value},
{key : value}
}
Code with the current pattern:
let str = "{p}This is a paragraph{/p} {img}(path/to/image) {ul}{li}This is a list item{/li}{li}Another list item{/li}{/ul}";
let regex = /\{(\w+)}(?:\()?([^\{\)]+)(?:\{\/1})?/g;
let match;
let matches = [];
while (match = regex.exec(str)) {
matches.push({ [match[1]]: match[2]})
}
console.log(matches)
Link to JSbin
I have realized I need the pattern to capture nested groups as well, and put these into an array – so the result for the above string would be:
[
{p : "This is a paragraph"},
{img : "path/to/image"},
{ul : ["This is a list item", "Another List item"]}
]
The idea here is to match each tag in order, so that the indexes of the array match the order they are found (i.e. first paragraph in the string above is array[0] and so forth).
If anyone has a bit of input on how I could structure the pattern that would be greatly appreciated.
I will not have more than 1 level deep nesting, if that makes any difference.
I am flexible to use a different markup for the ul if this would help, however I cannot use square brackets [text] due to conflicts with another function that generates the text I am trying to extract in this step.
Edit: An idea that hit me is to have a third capturing group to capture and push to the list-array, but I am unsure whether or not this would work in reality? I have not gotten it to work so far
JavaScript has no support for recursion within regular expressions, which would otherwise be a potential solution.
I would however go for a different solution:
You could rely on DOMParser -- available in browsers, or if you are on Node, there is similar functionality available in several modules.
To use it, you need to have an XML formatted string, so unless you want to use <p> style of tags, you'd first have to convert your string to that, making sure that content with < would need to get < instead.
Also the {img} tag would need to get a closing tag instead of the parentheses. So a replacement is necessary for that particular case.
Once that is out of the way, it is quite straightforward to get a DOM from that XML, which might already be good enough for you to work with, but it can be simplified to your desired structure with a simple recursive function:
const str = "{p}This is a paragraph{/p} {img}(path/to/image) {ul}{li}This is a list item{/li}{li}Another list item{/li}{/ul}";
const xml = str.replace(/\{img\}\((.*?)\)/g, "{img}$1{/img}")
.replace(/</g, "<")
.replace(/\{/g, "<").replace(/\}/g, ">");
const parser = new DOMParser();
const dom = parser.parseFromString("<root>" + xml + "</root>", "application/xml").firstChild;
const parse = dom => dom.nodeType === 3 ? dom.nodeValue.trim() : {
[dom.nodeName]: dom.children.length
? Array.from(dom.childNodes, parse).filter(Boolean)
: dom.firstChild.nodeValue
};
const result = parse(dom).root;
console.log(result);
The output is almost what you intended, except that that li elements are also represented as { li: "...." } objects.
I have a Chrome extension that replaces certain phrases on webpages. It uses a 2 dimensional array. The [i][1] replaces the text in provided in the [i][0] value.
for (var i = 0; i < array.length; i++) {
findAndReplaceDOMText(document.body, {
preset: 'prose',
find: array[i][0],
replace: array[i][1]
});
}
This code works fine yet it seems computationally expensive as it calls the findAndReplaceDOMText function multiple times rather than just once. Is it possible to move the for loop inside the function to just wrap the find and replace params? If so what would that look like? I can only get console errors trying this.
Edit: The function traverses the DOM looking for all visible human readable text that contains the regex phrase provided at find and replaces with the string provided at replace.
Without modifying the function's behaviour, you can't. What you could do is separating the find and replace passes.
Your strings are stored in a kind of difficult to transverse way, so let's flat them out:
var flatFind = array.map(function(elem){
return elem[0]
})
var flatReplace = array.map(function(elem){
return elem[1]
})
Then, you'd need to create a regex string that encompasses all your search strings:
var searchString = "/("+flatFind.join("|")+")/g"
Then pass it to the function, using a function to find the index of the match:
findAndReplaceDOMText(document.body, {
preset: 'prose',
find: searchString,
replace: function(portion, match){
var idx = flatFind.indexOf(match)
if(idx > -1) return flatReplace[idx]
else throw "hey, there's no replacement string for this!"
}
})
You could try to use the replace parameter as a function.
The find-configuration-property then needs to be a regular expression (RegExp-object) constructed of your search strings (like /first|second|third/g). Do not forget the g-modifier at the end.
As replace-configuration-property you then create a function that checks which string occurred (you get that as the second parameter to your function). According to the match you then return the corresponding value (for example if match is "first" then you return "1st". If match is "second" then you return "2nd" and so on).
I want get my program parameters from rel attribute of element, first of all is it logical ?
and the rel attribute may contain this string rel="_p|b|w=300|h=200" or rel="_p|w=300"
, so I use split to split my string with | pattern :
var attr = $(this).attr('rel').split('|');
for _p and b there is no problem because I can check with indexOf but for w and h I should use regular expression because the w and h value will be change.
how can I use regular expression in indexOf ?
sorry for my bad English
EDIT:
if (attr.indexOf('b')) {
blank = true;
}
First of all, that isn't a very elegant way of retrieving data. Anyway, if you really want to do that in that way, then you can use regexes as follows:
var matches = $(this).attr('rel').match(/w=(\d+)/);
var w = (matches && matches[1]) || defaultValue;
Also, if there can be multiple elements that end in 'w', then you'd better change your regex to something like:
var matches = $(this).attr('rel').match(/(?:^|\|)w=(\d+)/);
I would have suggested the use of custom attributes as well, however these would not be w3-conform as you want them to.
A simple way would be to split the parameters and then loop through and check each index whether it is one of the attributes you are expecting:
var cust_params = $(this).attr('rel').split('|'); //or this.rel as GGG suggested in a comment?
for(var i=0;i<cust_params.length;i++) {
if('_p'==cust_params[i]) {
//...
}
//...
if(cust_params[i].match(/w=(\d+)/)) {
//you could even do this without a regular expression
}
}
I hope this doesn't violate some good practice that I'm unaware of because I always feel like there must be a more elegant way when I do this kind of thing :) As it is I get a kind of quick-and-dirty feel about this.
Sorry there is no way you can do it in one command with normal javascript, indexOf just doesn't support regular expression.
You can either loop through the array or use jquery supported command for array.
For example: once you have the array attr as you like, you can use jQuery.grep() http://api.jquery.com/jQuery.grep/
a_equal = jQuery.grep(attr, function(a, i){
return (a.match(/=/) and i > 0); // modify this as you like
});
to create an array a_equal with all the assignment argument.
disclaimer.. code not yet tested.
Like Paolo Bergantino I'd also suggest using data-attributes, or you could store the data in a JSON (again, in a data attribute) and parse that:
<a href="#" data-info='{"width": "300", "height": "200", "color": "#fff", "etc": "foo"}'>
var info = JSON.parse(a.getAttribute('data-info'));
Edit: replaced eval with Phrogz's suggestion.
(With eval: eval('(' + a.getAttribute('data-info') + ')'))
I am in need of two regular expressions.
First of all I want to check if my URL contains the hashtag #videos. Then if it does, I want to get the value of the second #tag. That value could contain all kinds of characters;
http://local/default.php#videos#12345
http://local/default.php#videos#g5458f
http://local/default.php#videos#0-e4a5d
This is what I've got so far:
if (window.location.hash = 'videos') {
var url = window.location.hash,
id = url.match(regex-goes-here); // output e.g string '12345'
}
(Not sure if my extremely simple check (window.location.hash = 'videos') will work on two hashtags..? There is probably a better way of checking the URL, if so, please do tell :-)
You can get an array of tags like this:
var tags = window.location.hash.replace(/^#/, '').split('#');
In case of http://local/default.php#videos#12345, tags[0] will be videos and tags[1] will be 12345. You can use tags.length to determine how many tags there are.