IndexOf Returning Partial Match - javascript

I am having an issue with a piece of javascript that's evaluating to true when I do not want it to do so. When indexOf evaluates rec.name - which equals "CSI" - it returns true and triggers the continue line because the finalArr array contains an element named "CSIQ Group". However, that's not what I want, as I only want it to evaluate to true if it finds an element in the array that is an exact match.
Here's the snippet of code:
if(finalArr.join().indexOf(rec.name.toString()) > -1){
continue;
}
What can I change to prevent "CSI" from triggering the continue line when "CSIQ Group" is already in finalArr? Thanks!
Kind Regards,
Joseph

You could try using findIndexOf or in your case just find should do the trick, or even includes.
Something like this:
if(finalArr.includes(rec.name){
continue;
}
includes is great for a simple string match. If you want greater matching then you can try find. find will let you compare each element in the array against a certain condition and you can perform multiple checks on it.
if(!!finalArr.find(element => (element.toLowerCase() === name.rec.toLowerCase()){
continue;
}
I would, however, definitely recommend against converting your array to a string and trying to search it, especially for this case.

You could use RegExp to match the string exactly to CSI:
const pattern = /^CSI$/ // ^ - start of the string, $ - end of the string
pattern.test(rec.name.toString()) // true if only "CSI", false otherwise
You could use this to amend your code and do what you need if word CSI is found.

Related

Get id from url

I have the following example url: #/reports/12/expense/11.
I need to get the id just after the reports -> 12. What I am asking here is the most suitable way to do this. I can search for reports in the url and get the content just after that ... but what if in some moment I decide to change the url, I will have to change my algorythm.
What do You think is the best way here. Some code examples will be also very helpfull.
It's hard to write code that is future-proof since it's hard to predict the crazy things we might do in the future!
However, if we assume that the id will always be the string of consecutive digits in the URL then you could simply look for that:
function getReportId(url) {
var match = url.match(/\d+/);
return (match) ? Number(match[0]) : null;
}
getReportId('#/reports/12/expense/11'); // => 12
getReportId('/some/new/url/report/12'); // => 12
You should use a regular expression to find the number inside the string. Passing the regular expression to the string's .match() method will return an array containing the matches based on the regular expression. In this case, the item of the returned array that you're interested in will be at the index of 1, assuming that the number will always be after reports/:
var text = "#/reports/12/expense/11";
var id = text.match(/reports\/(\d+)/);
alert(id[1]);
\d+ here means that you're looking for at least one number followed by zero to an infinite amount of numbers.
var text = "#/reports/12/expense/11";
var id = text.match("#/[a-zA-Z]*/([0-9]*)/[a-zA-Z]*/")
console.log(id[1])
Regex explanation:
#/ matches the characters #/ literally
[a-zA-Z]* - matches a word
/ matches the character / literally
1st Capturing group - ([0-9]*) - this matches a number.
[a-zA-Z]* - matches a word
/ matches the character / literally
Regular expressions can be tricky (add expensive). So usually if you can efficiently do the same thing without them you should. Looking at your URL format you would probably want to put at least a few constraints on it otherwise the problem will be very complex. For instance, you probably want to assume the value will always appear directly after the key so in your sample report=12 and expense=11, but report and expense could be switched (ex. expense/11/report/12) and you would get the same result.
I would just use string split:
var parts = url.split("/");
for(var i = 0; i < parts.length; i++) {
if(parts[i] === "report"){
this.reportValue = parts[i+1];
i+=2;
}
if(parts[i] === "expense"){
this.expenseValue = parts[i+1];
i+=2;
}
}
So this way your key/value parts can appear anywhere in the array
Note: you will also want to check that i+1 is in the range of the parts array. But that would just make this sample code ugly and it is pretty easy to add in. Depending on what values you are expecting (or not expecting) you might also want to check that values are numbers using isNaN

Regexp: return array of matches without dividing character

I want to take a string with some special characters, and return an array of matches, but without the dividing characters, so the string
somebody#place&time[with,some,people]
will return
['somebody', 'place', 'time','with,some,people']
I currently have
(\w+)|(#\w+)|(&\w+)|\[([\w=\|,]+)\]
I can't just split on non-alphanumeric characters, because I want somebody to be able to provide
#place[with,some,people]
And the regex will return
[undefined, 'place', undefined,'width,some,people']
I'm pretty sure there is a way for me to remove the separation characters, but I can't seem to find it
--------------Update ----------------------------
As #CodeJockey mentioned, I didn't specify a language, because I thought this would be better as an open ended (as regexp works across multiple languages). I'm specifically using javascript and string.match to return an array of matches.
To answer #CodeJockey's other questions regarding the examples he provided
someone#area&time[] = ["someone","area","time",""]
#location = [undefined,"location",undefined, undefined]
#&tempus = [undefined, "","tempus",undefined]
#tempus?? = [undefined, "tempus??", undefined, undefined]
noone#nowhere&never[all,humans,that,ever,existed] = ["noone", "nowhere","ever","all,humans,that,ever,existed"]
savior#some undisclosed place&rapture:30[true,believers] = ["savoir","some",undefined, undefined] //as I have already cleaned the string so there are no spaces.
In the examples above, undefined or empty string don't really matter, either is acceptable as I need to be checking for that later.
$ php -r '$s="somebody#place&time[with,some,people]"; preg_match("/^([^#]*)#([^&]+)&([^[]+)[[]([^]]+)[]]/", $s, $a); unset($a[0]); print_r($a);'
Array
(
[1] => somebody
[2] => place
[3] => time
[4] => with,some,people
)
Note that the regex's first element expands with * instead of +, to allow for empty "somebody" strings per your question. Also note that an empty string is merely empty, not undefined.
Hopefully this may help somebody else. I thought I could do this with regexp using the match method in javascript, but I think I'm wrong.
I now think the correct way of doing this is the way sizzle.js (the DOM query engine for jQuery) does it. You can find it here.
https://github.com/jquery/sizzle/blob/master/dist/sizzle.js,
look for the matchExpr around line 110.
Using the fiddle you referenced in response to #ghoti, I modified and fixed the expression he suggested:
var to_parse = "name#place&time[with,other,people]";
var parse_array = to_parse.match(/^([^#]*)#([^&]+)&([^[]+)\[([^\]]+)\]/);
EITHER of the following statements remove the "entire match" element from index 0 and place the result in the parse_array variable, but only the first statement is chainable...
parse_array = parse_array.splice(1,4);
parse_array.splice(0,1);
a single statement version of the above is this:
var parse_array = to_parse.match(/^([^#]*)#([^&]+)&([^[]+)\[([^\]]+)\]/).splice(1,4);
to output the result nicely (by emphasizing the difference between the commas separating the array items and the commas separating the items contained within the string of the last item) to the console, use:
console.log('[\"' + parse_array.join("\", \"") + '\"]');
hope this helps you

Shared part in RegEx matched string

In following code:
"a sasas b".match(/sas/g) //returns ["sas"]
The string actually include two sas strings, a [sas]as b and a sa[sas] b.
How can I modify RegEx to match both?
Another example:
"aaaa".match(/aa/g); //actually include [aa]aa,a[aa]a,aa[aa]
Please consider the issue in general not just above instances.
A pure RexEx solution is preferred.
If you want to match at least one such "merged" occurrence, then you could do something like:
"a sasas b".match(/s(as)+/g)
If you want to retrieve the matches as separate results, then you have a bit more work to do; this is not a case that regular expressions are designed to handle. The basic algorithm would be:
Attempt a match. If it was unsuccessful, stop.
Extract the match you are interested in and do whatever you want with it.
Take the substring of the original target string, starting from one character following the first character in your match.
Start over, using this substring as the new input.
(To be more efficient, you could match with an offset instead of using substrings; that technique is discussed in this question.)
For example, you would start with "a sasas b". After the first match, you have "sas". Taking the substring that starts one character after the match starts, we would have "asas b". The next match would find the "sas" here, and you would again repeat the process with "as b". This would fail to match, so you would be done.
This significantly-improved answer owes itself to #EliGassert.
String.prototype.match_overlap = function(re)
{
if (!re.global)
re = new RegExp(re.source,
'g' + (re.ignoreCase ? 'i' : '')
+ (re.multiline ? 'm' : ''));
var matches = [];
var result;
while (result = re.exec(this))
matches.push(result),
re.lastIndex = result.index + 1;
return matches.length ? matches : null;
}
#EliGassert points out that there is no need to walk through the entire string character by character; instead we can find a match anywhere (i.e. do without the anchor), and then continue one character after the index of the found match. While researching how to retrieve said index, I found that the re.lastIndex property, used by exec to keep track of where it should continue its search, is in fact settable! This works rather nicely with what we intend to do.
The only bit needing further explanation might be the beginning. In the absence of the g flag, exec may never return null (always returning its one match, if it exists), thus possibly going into an infinite loop. Since, however, match_overlap by design seeks multiple matches, we can safely recompile any non-global RegExp as a global RegExp, importing the i and m options as well if set.
Here is a new jsFiddle: http://jsfiddle.net/acheong87/h5MR5/.
document.write("<pre>");
document.write('sasas'.match_overlap(/sas/));
document.write("\n");
document.write('aaaa'.match_overlap(/aa/));
document.write("\n");
document.write('my1name2is3pilchard'.match_overlap(/[a-z]{2}[0-9][a-z]{2}/));
document.write("</pre>");​
Output:
sas,sas
aa,aa,aa
my1na,me2is,is3pi
var match = "a sasas b".match(/s(?=as)/g);
for(var i =0; i != match.length; ++i)
alert(match[i]);
Going off of the comment by Q. Sheets and the response by cdhowie, I came up with the above solution: it consumes ONE character in the regular expression and does a lookahead for the rest of the match string. With these two pieces, you can construct all the positions and matching strings in your regular expression.
I wish there was an "inspect but don't consume" operator that you could use to actually include the rest of the matching (lookahead) string in the results, but there unfortunately isn't -- at least not in JS.
Here's a generic way to do it:
​String.prototype.match_overlap = function(regexp)
{
regexp = regexp.toString().replace(/^\/|\/$/g, '');
var re = new RegExp('^' + regexp);
var matches = [];
var result;
for (var i = 0; i < this.length; i++)
if (result = re.exec(this.substr(i)))
matches.push(result);
return matches.length ? matches : null;
}
Usage:
var results = 'sasas'.match_overlap(/sas/);
Returns:
An array of (overlapping) matches, or null.
Example:
Here's a jsFiddle in which this:
document.write("<pre>");​
document.write('sasas'.match_overlap(/sas/));
document.write("\n");
document.write('aaaa'.match_overlap(/aa/));
document.write("\n");
document.write('my1name2is3pilchard'.match_overlap(/[a-z]{2}[0-9][a-z]{2}/));
document.write("</pre>");​
returns this:
sas,sas
aa,aa,aa
my1na,me2is,is3pi
Explanation:
To explain a little bit, we intend for the user to pass a RegExp object to this new function, match_overlap, as he or she would do normally with match. From this we want to create a new RegExp object anchored at the beginning (to prevent duplicate overlapped matches—this part probably won't make sense unless you encounter the issue yourself—don't worry about it). Then, we simply match against each substring of the subject string this and push the results to an array, which is returned if non-empty (otherwise returning null). Note that if the user passes in an expression that is already anchored, this is inherently wrong—at first I stripped anchors out, but then I realized I was making an assumption in the user's stead, which we should avoid. Finally one could go further and somehow merge the resulting array of matches into a single match result resembling what would normally occur with the //g option; and one could go even further and make up a new flag, e.g. //o that gets parsed to do overlap-matching, but this is getting a little crazy.

How can I make javascript match the start of a string?

I have the following coce:
if (link.action === "Create") {
However my link.action could be:
Create xxxx
Is there a way I can change this match so it just checks for the start being "Create" ?
Just Check string.indexOf(string_to_check). It returns the index number for a 'string_to_check', if it exists in the string. Any in your case, you want the string start with "Create", so the index should be always 0 in your case.
So, You can try this
if (link.action.indexOf("Create") == 0) {
Use a regular expression.
if (link.action.match(/^Create/) {
}
^ is a special character: an anchor which matches only the beginning of the input.
More reading on regex in general: http://www.regular-expressions.info
link.action.slice(0,6)=="Create"
Will also work as you like as above mentioned methods. For further read String object reference in java script.

Javascript wildcard variable?

The value of product_id might be some combination of letters and numbers, like: GB47NTQQ.
I want to check to see if all but the 3rd and 4th characters are the same.
Something like:
if product_id = GBxxNTQQ //where x could be any number or letter.
//do things
else
//do other things
How can I accomplish this with JavaScript?
Use regular expression and string.match(). Periods are single wildcard characters.
string.match(/GB..NTQQ/);
Use a regular expression match:
if ('GB47NTQQ'.match(/^GB..NTQQ$/)) {
// yes, matches
}
Answers so far have suggested match, but test is likely more appropriate as it returns true or false, whereas match returns null or an array of matches so requires (implicit) type conversion of the result within the condition.
if (/GB..NTQQ/.test(product_id)) {
...
}
if (myString.match(/regex/)) { /*Success!*/ }
You can find more information here: http://www.regular-expressions.info/javascript.html

Categories