Slice method is not consistent - javascript

I've created a function to parse a string of text and look for a combination of key words. The key words and their indexes are then captured and used later on to reassemble the full string from first to last keyword, including all words in between. I'm using array.slice to pull the string from the array however it's inconsistent and sometimes requires incrementing\decrementing the second value in order to get the exact match. I've created a jsfiddle http://jsfiddle.net/jkeohan/g7vdgg1a/4/ to demo it.
line 50 and 64 the ones where slice is being used and in one instance index+1 is used and the other index-1. Both produce the same results, most of the time.
var phrase = (datafull.slice( (comparearray[0].index-1),
(comparearray[comparearray.length-2].index+1) ) ).join(" ")
matchingString = (datafull.slice( (comparearray[0].index-1),
(comparearray[comparearray.length-3].index-1) ) ).join(" ")
Any ideas?

Related

How does split and join work in JavaScript?

But still dont understand : as in input box initially there is no data , however when the user starts typing the functions starts invoking the method in it , however the first line will [ $(this).val().split("-").join(""); ] will then look for the hyphen character to split into ... but as if the data typed by the user dosent contains any hyphens so what has to be replaced...??? like you explained above e.g. split("-") on "a-b-c" will give ["a","b","c"] ....this data already contains the hyphen character and which gets replaced with the character that we specify in brackets. Again at the other hand i dont understand this too : foo = foo.match(new RegExp('.{1,4}', 'g')).join("-"); , why there is single quotes in the RegExp, and what for the 1,4 stands for ..??? as far a i know that it must be meant for minimum 1 and maximum 4 charachters..? could you please help me understanding this..??? Appreciate your help
The function calls are evaluated from left to right. First val(), then split("-")and then join("").
What this does, is that it reads the value and since it seems to be a credit card number, the value will be something like 1234-5678-9012-3456.
The next thing is split the numbers at the hyphens with split("-"). This will result in a kind of list ['1234', '5678', '9012', '3456'].
This list is then joined using "" (Nothing actually) resulting in 1234567890123456, the number without the hyphens.
The same thing could be achieved with
$(this).val().replace(/-/g, "")
using Regular Expressions.
Hope this clarifies stuff!
$(this).val()
Gets the value of the element:
.split("-")
Build an array of strings that splits on '-' (hyphen). Basically, when you find '-' in the string, add it to i.e. 'foo-bar' becomes ['foo', 'bar'].
.join("");
Take the array and join each element back together with an empty string i.e. ['foo', 'bar'] becomes 'foobar'.
Split and join in one line
const result = "7.83".split('.').reduce((first, second) => `${first}' ${second}"`)
console.log(result)
7' 83"

Javascript selecting to save one index of split()

I have a value - toggle-save_2
I want to extract the 2 part. The part after the underscore will always be what i need but the length of the former part, which in this case is toggle-save_, may vary (eg. notoggle-val_45). Though this length may vary it will always be separated from the end number by an underscore.
Right now I am using this
var current = this.id.split('_');
current = current[1];
to select the number.
What would be cool is if I could pass a variable to the split to only give me the second index of the result from the split.
Just select the 2nd index when you do the split.
var current = this.id.split('_')[1];
The best solution here would be to use lastIndexOf and substring, like this
function getLastPart(strObject) {
return strObject.substring(strObject.lastIndexOf("_") + 1);
}
console.log(getLastPart("toggle-save_2"));
// 2
console.log(getLastPart("notoggle-save_45"));
// 45
It is better for this case because, you already know that the _ will be somewhere near the last position. Since lastIndexOf starts from the last position, it would find _ very soon and all we need to do is to get the rest of the string from the next position.
There are often times I am breaking up a string where I only need the very last value of the result of String.prototype.split and consider the rest to be garbage no matter how many values the split produced.
When those cases arise, I like to chain Array.prototype.pop off of the split
var s = 'toggle-save_2',
current = s.split('_').pop();
The split method can only be limited from the end, and it will always return an array.
You don't need to use split, you can use string operations to get part of the string:
var current = this.id.substr(this.id.indexOf('_') + 1);

JavaScript regex back references returning an array of matches from single capture group (multiple groups)

I'm fairly sure after spending the night trying to find an answer that this isn't possible, and I've developed a work around - but, if someone knows of a better method, I would love to hear it...
I've gone through a lot of iterations on the code, and the following is just a line of thought really. At some point I was using the global flag, I believe, in order for match() to work, and I can't remember if it was necessary now or not.
var str = "#abc#def#ghi&jkl";
var regex = /^(?:#([a-z]+))?(?:&([a-z]+))?$/;
The idea here, in this simplified code, is the optional group 1, of which there is an unspecified amount, will match #abc, #def and #ghi. It will only capture the alpha characters of which there will be one or more. Group 2 is the same, except matches on & symbol. It should also be anchored to the start and end of the string.
I want to be able to back reference all matches of both groups, ie:
result = str.match(regex);
alert(result[1]); //abc,def,ghi
alert(result[1][0]); //abc
alert(result[1][1]); //def
alert(result[1][2]); //ghi
alert(result[2]); //jkl
My mate says this works fine for him in .net, unfortunately I simply can't get it to work - only the last matched of any group is returned in the back reference, as can be seen in the following:
(additionally, making either group optional makes a mess, as does setting global flag)
var str = "#abc#def#ghi&jkl";
var regex = /(?:#([a-z]+))(?:&([a-z]+))/;
var result = str.match(regex);
alert(result[1]); //ghi
alert(result[1][0]); //g
alert(result[2]); //jkl
The following is the solution I arrived at, capturing the whole portion in question, and creating the array myself:
var str = "#abc#def#ghi&jkl";
var regex = /^([#a-z]+)?(?:&([a-z]+))?$/;
var result = regex.exec(str);
alert(result[1]); //#abc#def#ghi
alert(result[2]); //jkl
var result1 = result[1].toString();
result[1] = result1.split('#')
alert(result[1][1]); //abc
alert(result[1][2]); //def
alert(result[1][3]); //ghi
alert(result[2]); //jkl
That's simply not how .match() works in JavaScript. The returned array is an array of simple strings. There's no "nesting" of capture groups; you just count the ( symbols from left to right.
The first string (at index [0]) is always the overall matched string. Then come the capture groups, one string (or null) per array element.
You can, as you've done, rearrange the result array to your heart's content. It's just an array.
edit — oh, and the reason your result[1][0] was "g" is that array indexing notation applied to a string gets you the individual characters of the string.

What is the fastest implementation of ColdFusion's listFindNoCase function in Javascript?

I've grown spoiled by ColdFusion's lists, and have run across a situation or two where a comma delimited list shows up in Javascript. Is there an equivalent of listFindNoCase('string','list'), or a performant way to implement it in Javascript?
Oh, and it should be able to handle list items with commas, like:
( "Smith, John" , "Doe, Jane" , "etc..." )
That's what is really tripping me up.
FYI: jList's implementation: https://github.com/davidwaterston/jList
Although, this will fail your requirement that "it should be able to handle list items with commas"
listFind : function (list, value, delimiter) {
delimiter = (typeof delimiter === "undefined") ? "," : delimiter;
var i,
arr = list.split(delimiter);
if (arr.indexOf !== undefined) {
return arr.indexOf(value) + 1;
}
for (i = 0; i < list.length; i += 1) {
if (arr[i] === value) {
return i + 1;
}
}
return 0;
},
listFindNoCase : function (list, value, delimiter) {
delimiter = (typeof delimiter === "undefined") ? "," : delimiter;
list = list.toUpperCase();
value = String(value).toUpperCase();
return this.listFind(list, value, delimiter);
},
One relevant observation here is that CF lists themselves don't support the delimiter char also being part of the data. Your sample "list" of '"Smith, John", "Doe, Jane"' is a four-element comma-delimited list of '"Smith', 'John"', '"Doe', 'Jane"'. To fulfil your requirement here you don't want a JS equiv of CF's listFindNoCase(), because listFindNoCase() does not actually fulfill your requirement in from the CF perspective, and nothing native to CF does. To handle elements that have embedded commas, you need to use a different char as a delimiter.
TBH, CF lists are a bit rubbish (for the reason cited above), as they're only really useful in very mundane situations, which a) don't often crop up; b) aren't better served via an array anyhow. One observation to make here is you are asking about a performant solution here: not using string-based lists would be the first step in being performant (this applies equally to CF as it does to JS: CF's string-based lists are not at all performant).
So my first answer here would be: I think you ought to revise your requirement away from using lists, and look to use arrays instead.
With that in mind, how is the data getting to JS? Are you some how stuck with using a string-based list? If not: simply don't. If your source data is a string-based list, are you in the position to convert it to an array first? You're in trouble with the "schema" of your example list as I mentioned before: from CF's perspective you can't have a comma being both a delimiter and data. And you do have a bit of work ahead of you writing code to identify that a quoted comma is data, and a non-quoted comma is a delimiter. You should have a look around at CSV-parsing algorithms to deal with that sort of thing.
However if you can change the delimiter (to say a pipe or a semi-colon or something that will not show up in the data), then it's easy enough to turn that into an array (listToArray() in CF, or split() in JS). Then you can just use indexOf() as others have said.
For the sake of sh!ts 'n' giggles, if you were stuck with a string - provided you could change the delimiter - you could do this, I think:
use indexOf() to find the position of the first match of the substring in the string, you will need to use a regex to match the substring which is delimited by your delimiter char, or from the beginning of the string to a delimiter char, or from a delimiter char to the end of the string with no intermediary delimiter chars. I could come up with the regex for this if needs must. This will not be list-aware yet, but we know where it'll be in the string.
Take a substring of the original string from the beginning to the position indexOf() returned.
Use split() on that, splitting on the delimiter
The length of the ensuing array will be the position in the original list that the match was at.
However I stress you should not do that. Use an array instead of a string from the outset.
You can use indexOf combined with .toLowerCase()
var list = '"Smith, John" , "Doe, Jane" , "etc..."';
if(list.toLowerCase().indexOf('"Smith, John"'))
If you need an exact match, like "Smith" when "Smithson" exists, just pad the strings with your delimiter. For example, let's say your delimiter is a semi-colon (because you have commas in your string), pad the left and right sides of your string like so:
";Smith, John;Doe, Jane;"
Also pad the search value, so if you're looking for Smith, the value would become:
";Smith;"
.toLowerCase().indexOf() would return -1 (not found). But ";Smith, John;" would return 0

Regex to extract substring, returning 2 results for some reason

I need to do a lot of regex things in javascript but am having some issues with the syntax and I can't seem to find a definitive resource on this.. for some reason when I do:
var tesst = "afskfsd33j"
var test = tesst.match(/a(.*)j/);
alert (test)
it shows
"afskfsd33j, fskfsd33"
I'm not sure why its giving this output of original and the matched string, I am wondering how I can get it to just give the match (essentially extracting the part I want from the original string)
Thanks for any advice
match returns an array.
The default string representation of an array in JavaScript is the elements of the array separated by commas. In this case the desired result is in the second element of the array:
var tesst = "afskfsd33j"
var test = tesst.match(/a(.*)j/);
alert (test[1]);
Each group defined by parenthesis () is captured during processing and each captured group content is pushed into result array in same order as groups within pattern starts. See more on http://www.regular-expressions.info/brackets.html and http://www.regular-expressions.info/refcapture.html (choose right language to see supported features)
var source = "afskfsd33j"
var result = source.match(/a(.*)j/);
result: ["afskfsd33j", "fskfsd33"]
The reason why you received this exact result is following:
First value in array is the first found string which confirms the entire pattern. So it should definitely start with "a" followed by any number of any characters and ends with first "j" char after starting "a".
Second value in array is captured group defined by parenthesis. In your case group contain entire pattern match without content defined outside parenthesis, so exactly "fskfsd33".
If you want to get rid of second value in array you may define pattern like this:
/a(?:.*)j/
where "?:" means that group of chars which match the content in parenthesis will not be part of resulting array.
Other options might be in this simple case to write pattern without any group because it is not necessary to use group at all:
/a.*j/
If you want to just check whether source text matches the pattern and does not care about which text it found than you may try:
var result = /a.*j/.test(source);
The result should return then only true|false values. For more info see http://www.javascriptkit.com/javatutors/re3.shtml
I think your problem is that the match method is returning an array. The 0th item in the array is the original string, the 1st thru nth items correspond to the 1st through nth matched parenthesised items. Your "alert()" call is showing the entire array.
Just get rid of the parenthesis and that will give you an array with one element and:
Change this line
var test = tesst.match(/a(.*)j/);
To this
var test = tesst.match(/a.*j/);
If you add parenthesis the match() function will find two match for you one for whole expression and one for the expression inside the parenthesis
Also according to developer.mozilla.org docs :
If you only want the first match found, you might want to use
RegExp.exec() instead.
You can use the below code:
RegExp(/a.*j/).exec("afskfsd33j")
I've just had the same problem.
You only get the text twice in your result if you include a match group (in brackets) and the 'g' (global) modifier.
The first item always is the first result, normally OK when using match(reg) on a short string, however when using a construct like:
while ((result = reg.exec(string)) !== null){
console.log(result);
}
the results are a little different.
Try the following code:
var regEx = new RegExp('([0-9]+ (cat|fish))','g'), sampleString="1 cat and 2 fish";
var result = sample_string.match(regEx);
console.log(JSON.stringify(result));
// ["1 cat","2 fish"]
var reg = new RegExp('[0-9]+ (cat|fish)','g'), sampleString="1 cat and 2 fish";
while ((result = reg.exec(sampleString)) !== null) {
console.dir(JSON.stringify(result))
};
// '["1 cat","cat"]'
// '["2 fish","fish"]'
var reg = new RegExp('([0-9]+ (cat|fish))','g'), sampleString="1 cat and 2 fish";
while ((result = reg.exec(sampleString)) !== null){
console.dir(JSON.stringify(result))
};
// '["1 cat","1 cat","cat"]'
// '["2 fish","2 fish","fish"]'
(tested on recent V8 - Chrome, Node.js)
The best answer is currently a comment which I can't upvote, so credit to #Mic.

Categories

Resources