I have been trying to use a simple jQuery operation to dynamically match and store all anchor tags and their texts on the page. But I have found a weird behavior. When you are using match() or exec(), if you designate the needle as a separate RegExp object or a pattern variable, then your query matches only one instance among dozens in the haystack.
And if you designate the pattern like this
match(/needle/gi)
then it matches every instance of the needle.
Here is my code.
You can even fire up Firebug and try this code right here on this page.
var a = {'text':'','parent':[]};
$("a").each(function(i,n) {
var module = $.trim($(n).text());
a.text += module.toLowerCase() + ',' + i + ',';
a.parent.push($(n).parent().parent());
});
var stringLowerCase = 'b';
var regex = new RegExp(stringLowerCase, "gi");
//console.log(a.text);
console.log("regex 1: ", regex.exec(a.text));
var regex2 = "/" + stringLowerCase + "/";
console.log("regex 2: ", a.text.match(regex2));
console.log("regex 3: ", a.text.match(/b/gi));
For me it is returning:
regex 1: ["b"]
regex 2: null
regex 3: ["b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b"]
Can anyone explain the root of this behavior?
EDIT: I forgot to mention that for regex1, it doesn't make any difference whether you add the flags "gi" for global and case insensitive matching. It still returns only one match.
EDIT2: SOlved my own problem. I still don't know why one regex1 matches only one instance, but I managed to match all instances using the match() and the regex1.
So..this matches all and dynamically!
var regex = new RegExp(stringLowerCase, "gi");
console.log("regex 2: ", a.text.match(regex));
This is not unusual behaviour at all. In regex 1 you are only checking for 1 instance of it where in regex 3 you have told it to return all instances of the item by using the /gi argument.
In Regex 2 you are assuming that "/b/" === /b/ when it doesn't. "/b/" !== /b/. "/b/" is a string that is searching so if you string has "/b/" in it then it will return while /b/ means that it needs to search between the slashes so you could have "abc" and it will return "b"
I hope that helps.
EDIT:
Looking into it a little bit more, the exec methods returns the first match that it finds rather than all the matches that it finds.
EDIT:
var myRe = /ab*/g;
var str = "abbcdefabh";
var myArray;
while ((myArray = myRe.exec(str)) != null)
{
var msg = "Found " + myArray[0] + ". ";
msg += "Next match starts at " + myRe.lastIndex;
console.log(msg);
}
Having a look at it again it definitely does return the first instance that it finds. If you looped through it then would return more.
Why it does this? I have no idea...my JavaScript Kung Fu clearly isnt strong enough to answer that part
The reason regex 2 is returning null is that you're passing "/b/" as the pattern parameter, while "b" is actually the only thing that is actually part of the pattern. The slashes are shorthand for regex, just as [ ] is for array. So if you were to replace that to just new regex("b"), you'd get one match, but only one, since you're omitting the "global+ignorecase" flags in that example. To get the same results for #2 and #3, modify accordingly:
var regex2 = stringLowerCase;
console.log("regex 2: ", a.text.match(regex2, "gi"));
console.log("regex 3: ", a.text.match(/b/gi));
regex2 is a string, not a RegExp, I had trouble too using this kind of syntax, tho i'm not really sure of the behavior.
Edit : Remebered : for regex2, JS looks for "/b/" as a needle, not "b".
Related
Normal split works like this:
var a = " a #b c "
console.log(a.split(" "))
["", "a", "b", "c", ""]
But my expected output is: [" a", "#b", "c "] it is possible? And how?
One option is to use a regular expression and require word boundaries before and after the space:
var a = " a b c "
console.log(a.split(/\b \b/));
If non-word characters are allowed as well, you can use match instead - either match spaces at the beginning of the string, followed by non-spaces, or match non-spaces followed by spaces and the end of the string, or match non-spaces without restriction:
const a = " foo #bar c "
console.log(
a.match(/^ *\S+|\S+ *$|\S+/g)
);
Lookbehind is another option, but it's not supported enough to be reliable in production code yet.
How about
a.split(/(?!^) (?!$)/)
If there may be more than one space and lookbehinds are supported then
a.split(/(?<!^ *) +(?! *$)/)
You can trim the string before the split, for example:
var a = " a b c ";
a = a.trim();
console.log(a.split(" "));
update
i was wrong to read the expected output, the result of my suggested code it's:
["a", "b", "c"] and not [" a", "b", "c "]
I have an object with strings properties I want to compare to multiple user inputs using case insensitivity. My goal is to match input strings to object strings to increment the associated value by 1 (if it's a match).
var objArr = [
{"O": 0},
{"foo": 0},
{"faa": 0},
{"A": 0}
];
Everything is working smoothly except for the case insensitivity. The RegExp method I used just looks for one letter instead of the whole word. I'm probably not using the right syntax, but I can't find results on google which explain the /i flag along with a variable.
My closest try was :
var re = new RegExp(b, "i"); //problem here
if (allinputs[i].value.match(re)) { //and here
This code indeed allows case insensitivity but it doesn't look for the whole object property string and stops for letters. For exemple typing "foo" will result in a match to "O" because it contains the letter "O", and the property "O" is before "foo". Accordingly, typing "faa" matches to "faa" and not "A", because "faa" is before "A" in the objects array. Strings that don't exist in my object like "asfo" will still be matched to "O" because of the one common letter.
Is there a way to search for the whole property string with case insensivity using the regExp /i flag ? I want to avoid using .toUpperCase() or .toLowerCase() methods if possible.
Fiddle here : https://jsfiddle.net/Lau1989/b39Luhcu/
Thanks for your help
To check that a regex matches the entire string, you can use the assert beginning character (^) and assert end ($).
For example, hello matches e but not ^e$.
For your code, just prepend ^ to the regex and append $:
var re = new RegExp("^" + b + "$", "i");
fiddle
Edit: Some characters have special meanings in regexes (^, $, \, ., *, etc). If you need to use any of these characters, they should be escaped with a \. To do this, you can use this simple replace:
str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
So, your regex will end up being
new RegExp("^" + b.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$", "i");
See this question for more about escaping a regex.
You could also just convert the two strings to lowercase and then compare them directly. This will allow you to use special characters as well.
if (stringA.toLowerCase() == stringB.toLowerCase())) {
...
}
Your approach was almost right, but you need limitate your regular expression to avoid an any match using ^ (start of string) and $ (end of string).
Here is a code that I made that may fit to your need:
function process()
{
var allinputs = document.querySelectorAll('input[type="text"]');
var list = new Array();
var input = "";
objArr.map(function(value, index, array){ list.push(Object.keys(value))})
for(var i = 0; i < allinputs.length; i++)
{
input = allinputs[i];
if(input.value)
{
list.map(function( item, index, array ) {
var re = new RegExp("^"+input.value+"$", "i");
if(item.toString().match(re))
{
allinputs[i].value = "1";
objArr[index][item] += 1;
allinputs[i].style.backgroundColor = "lime";
document.getElementById('output').innerHTML += item + " : " + objArr[index][item] + "<br />";
}
});
}
}
}
The first thing here is create a list of keys from your objArr, so we can access the key names easily to match with what you type
objArr.map(function(value, index, array){ list.push(Object.keys(value))})
Then the logic stills the same as you already did, a for loop in all inputs. The difference is that the match will occur on list array instead of the objArr. As the index sequence of list and objArr are the same, it's possible to access the object value to increment.
I used the .map() function in the list array, bit it's also possible use a for loop if you prefer, both method will work.
I hope this help you!
How can I extract the text between all pairs of square brackets from the a string "[a][b][c][d][e]", so that I can get the following results:
→ Array: ["a", "b", "c", "d", "e"]
→ String: "abcde"
I have tried the following Regular Expressions, but to no avail:
→ (?<=\[)(.*?)(?=\])
→ \[(.*?)\]
Research:
After having searched in Stack Overflow, I have only found two solutions, both of which using Regular Expressions and they can be found here:
→ (?<=\[)(.*?)(?=\]) (1)
(?<=\[) : Positive Lookbehind.
\[ :matches the character [ literally.
(.*?) : matches any character except newline and expands as needed.
(?=\]) : Positive Lookahead.
\] : matches the character ] literally.
→ \[(.*?)\] (2)
\[ : matches the character [ literally.
(.*?) : matches any character except newline and expands as needed.
\] : matches the character ] literally.
Notes:
(1) This pattern throws an error in JavaScript, because the lookbehind operator is not supported.
Example:
console.log(/(?<=\[)(.*?)(?=\])/.exec("[a][b][c][d][e]"));
Uncaught SyntaxError: Invalid regular expression: /(?<=\[)(.*?)(?=\])/: Invalid group(…)
(2) This pattern returns the text inside only the first pair of square brackets as the second element.
Example:
console.log(/\[(.*?)\]/.exec("[a][b][c][d][e]"));
Returns: ["[a]", "a"]
Solution:
The most precise solution for JavaScript that I have come up with is:
var string, array;
string = "[a][b][c][d][e]";
array = string.split("["); // → ["", "a]", "b]", "c]", "d]", "e]"]
string = array1.join(""); // → "a]b]c]d]e]"
array = string.split("]"); // → ["a", "b", "c", "d", "e", ""]
Now, depending upon whether we want the end result to be an array or a string we can do:
array = array.slice(0, array.length - 1) // → ["a", "b", "c", "d", "e"]
/* OR */
string = array.join("") // → "abcde"
One liner:
Finally, here's a handy one liner for each scenario for people like me who prefer to achieve the most with least code or our TL;DR guys.
Array:
var a = "[a][b][c][d][e]".split("[").join("").split("]").slice(0,-1);
/* OR */
var a = "[a][b][c][d][e]".slice(1,-1).split(']['); // Thanks #xorspark
String:
var a = "[a][b][c][d][e]".split("[").join("").split("]").join("");
I don't know what text you are expecting in that string of array, but for the example you've given.
var arrStr = "[a][b][c][d][e]";
var arr = arrStr.match(/[a-z]/g) --> [ 'a', 'b', 'c', 'd', 'e' ] with typeof 'array'
then you can just use `.concat()` on the produced array to combine them into a string.
if you're expecting multiple characters between the square brackets, then the regex can be (/[a-z]+/g) or tweaked to your liking.
I think this approach will be interesting to you.
var arr = [];
var str = '';
var input = "[a][b][c][d][e]";
input.replace(/\[(.*?)\]/g, function(match, pattern){
arr.push(pattern);
str += pattern;
return match;//just in case ;)
});
console.log('Arr:', arr);
console.log('String:', str);
//And trivial solution if you need only string
var a = input.replace(/\[|\]/g, '');
console.log('Trivial:',a);
I don't know if this has been asked before, because English is not my first language and I don't know the keywords to search.
So basically I have the following input element,
<input type="email" name="person[0].email" />
I would like to split the name into 3 parts like ["person", "0", "email"].
I have tried using /(\[[^[\]]])|\./ but it gives ["person", "[0]", "", undefined, "email"].
Also, for a[0][1].b[3].c, it should output ["a", "0", "1", "b", "3", "c"]
You can use .match instead of .split
console.log("person[0].email".match(/\w+/g));
Note (thanks #npinti): in case if in name will be _ my first example will match also _, so in this case you need just use regexp like this
console.log("person[0].email".match(/[A-Za-z0-9]+/g));
Seems like you want to break on anything which is not a letter or a number, thus you could use this: [^A-Za-z0-9]+. An example of the expression is available here.
You can use this split:
var m = person[0].email".split(/[.\[\]]+/g)
//=> ["person", "0", "email"]
OR:
m = "a[0][1].b[3].c".split(/[.\[\]]+/g)
//=> ["a", "0", "1", "b", "3", "c"]
If you always have the following format: name[i].prop, you can do this without regular expressions:
function splitName(s)
{
var parts1 = s.split('].');
var parts2 = parts1[0].split('[');
return [parts2[0], parts2[1], parts1[1]];
}
document.body.innerHTML += JSON.stringify(splitName('name[i].prop')) + '<br/>';
document.body.innerHTML += JSON.stringify(splitName('person[0].email')) + '<br/>';
document.body.innerHTML += JSON.stringify(splitName('a[0].b')) + '<br/>';
It is less elegant, not universal and works only for the specified format. However, there are no regular expressions and if you work only with this format - then why not? :)
This might be a simple question but, how do i split words... for example
a = "even, test"
I have used .split to seperate the text with space.
so the result came is like
a = "even,"
b = "test"
But, how do I remove the 'comma' here?
But in some conditions it might get "even test" and in some conditions i might get "even, test". All are dynamic, so how do i check it for both?
Thanks
Firstly, the split() function is not jQuery - it is pure Javascript.
Did you try doing split with a comma and a space? That would have worked just fine in your case:
var result = input.split(', ');
For more complex splits, you can use regular expression pattern matching to allow multiple commas or spaces between the two fields:
var result = input.split(/[, ]+/);
but you probably don't need to go that far in your case.
I think is better to use something like this:
text.match(/[a-z'\-]+/gi);
Example:
var e=function()
{
var r=document.getElementById('r');
var x=document.getElementById('t').value.match(/[a-z'\-]+/gi);
for(var i=0;i<x.length;i++)
{
var li=document.createElement('li');
li.innerText=x[i];
r.appendChild(li);
}
}
<div style="float:right;width:18%">
<ol id="r" style="display:block;width:auto;border:1px inner;overflow:scroll;height:8em;max-height:10em;"></ol>
<button onclick="e()">Extract words!</button>
</div>
<textarea id="t" style="width:70%;height:12em">even, test; spider-man
But saying o'er what I have said before:
My child is yet a stranger in the world;
She hath not seen the change of fourteen years,
Let two more summers wither in their pride,
Ere we may think her ripe to be a bride.
—Shakespeare, William. The Tragedy of Romeo and Juliet</textarea>
I found a list of word separators in Sublime Text default settings.
Here's how to split with it, with some Unicode support (the defined separators are not Unicode though):
{ // word_separators: ./\()"'-,;<>~!##$%^&*|+=[]{}`~?: (32)
function splitByWords(str = '', limit = undefined) {
return str.split(/[-./\\()"',;<>~!##$%^&*|+=[\]{}`~?:]/u, limit)
}
function reverseString(str) {
let newString = ''
for (let i = str.length - 1; i >= 0; i--)
newString += str[i]
return newString
}
const str = '123.x/x\\x(x)x"x\'x-x:x,789;x<x>x~x!x#x#x$x%x^x&x*x|x+x=x[x]x{x}x`x~x?456'
console.log(splitByWords(str)) // (33) ["123", "x", "x", "x", "x", "x", "x", "x", "x", "x", "789", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "456"]
console.log(splitByWords(str, 1)) // ["123"]
console.log(splitByWords(reverseString(str), 1)) // ["654"]
}
For some reason the - has to be at the beginning, and the : at the end.
Edit: you might want to add \s (after the -) to count whitespace as separator
Just use this code:
var a = "even, test";
var words = a.split(", ");
a.split(',')
or
var re = /\s*,\s*/
var newA = a.split(re);
I think you could do it like this:
var a= 'even,'
var newA = a.slice(0, -1)
This will remove the last char from a given string.
And to check if the string contains a comma, I would do the following:
if (a.indexOf(",") >= 0){
//contains a comma
} else {
//no comma
}
I am a javascript beginner, so this probably is not the best way to do it, but nevertheless it works.
Hej Harry
if the comma is the separator you can call split with the comma
Ex:
var newColls = myString.split(",");
and not split with space.
GL