Regex using .match in javascript brings the result more than once - javascript

I have this regex \w?(row-)\d+ and I'm trying to get bits from the html using javascript
so this is a part of my html:
<div class="col-md-1"><input class="form-control row-25 all" type="text" value="NA" onchange="validate('rep',this)" disabled></div>
<div class="col-md-1"><input class="form-control row-25 all" type="text" value="$15" onchange="validate('rep',this)" disabled></div>
<div class="col-md-1"><input class="form-control row-25" type="text" value="Per number" disabled></div>
and that's my js var rowIndex = element.className.match(/\w?(row-)\d+/);
What i'm getting from that .match function is this
row-25, row-
What I'm trying to get is only
row-25
What am i doing wrong here? Thanks.
UPDATE:
Actually I have found an answer to how to get what I need but that doesn't explain the output still, what I did is I chose to read rowIndex[0], and neglect the rest, however why is "row-" appearing anyway?

Because match() returns either null or an array of results. These results are the full pattern (\w?(row-)\d+) as well as the subpatterns (row-) represented by the bits enclosed within parentheses. That said, as it stands, your regular expression will also match classes like arrow-25 or row-25xyz. Here is a workaround if needed :
/(?:^|\s)(row-\d+)(?:\s|$)/
Dissection :
(...) captures subpattern
(?:...) doesn't capture subpattern
(?:^|\s) the beginning of the string or a whitespace
(row-\d+) "row-" plus at least one digit (subpattern 1)
(?:\s|$) a whitespace or the end of the string
If you want to extract only the number :
/(?:^|\s)row-(\d+)(?:\s|$)/
Dissection :
(?:^|\s) the beginning of the string or a whitespace
row- "row-"
(\d+) at least one digit (subpattern 1)
(?:\s|$) a whitespace or the end of the string
Usage example :
var r = /(?:^|\s)row-(\d+)(?:\s|$)/,
n = el.className.match(r);
if (n) { // if n is not null
n = n[1]; // set n as subpattern 1
}
With a class name like form-control row-25 all, n will be 25.
Also read :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match
http://www.javascriptkit.com/javatutors/redev2.shtml

I you want to get row-25 use:
rowIndex = element.className.match(/\w?(row-\d+)/);

Change your regex to:
/\w?row-\d+/
Since your regex has this capturing group /(row-)/ therefore in the result you are getting 2 elements in the array:
Full matched input string
Captured group
Since you don't really need capturing group just don't put brackets around row-

Related

regex for input mask - comma separated list of up to three characters per item

I have an input field, which I want to limit as follows:
The input will be a comma-separated list
Each string in the list must be limited to 1..3 characters
The list can have as many items as the user wants
some examples:
1,4,6a,16b
1
abc,def,ghi,jkl,mno,pqr,stu,vwx,yzz
I have found the following jsfiddle: https://jsfiddle.net/2x8y1dhL/ which provides a starting point for creating an input mask, but it assumes a fixed number of items in the list, and a fixed length of each input.
What I want is the following logic:
after the user inputs the third character in a row that isn't a comma, a comma is automatically inserted
I have worked on the jsfiddle you have found. Some notes:
You have not specified valid/invalid characters, but the examples given seem to suggest "alpha-numeric plus comma"
Consecutive commas are allowed as it's not specified otherwise.
The meat of the matter are the two functions createMask and destroyMask:
function createMask(string){
return string.replace(/(\w{3})(?!,)(.+)$/g,"$1,$2");
}
function destroyMask(string){
return string.replace(/[^0-9A-Z,]/ig,'');
}
Update 1: Pasting input that is longer than six characters - i.e. needs to be split more than once - turned out to be problematic with the original answer. An explicit loop is needed as the g modifier does not help with that regex. Here's the updated fiddle:
function createMask(string){
let s = string;
let t;
do {
t = s;
s = s.replace(/(\w{3})(?!,)(.+)$/,"$1,$2");
} while (s !== t)
return s;
}
Update 2: However, we can get away without an explicit loop with this alternative regex that only uses a single capture - updated fiddle:
function createMask(string){
return string.replace(/(\w{3})(?!,|$)/g,"$1,");
}
You can repeat optional repetitions of 3 word characters followed by a comma and then match 3 word characters asserting a word char to the right.
^(?:\w{3},)*\w{3}(?=\w)
Regex demo | Forked fiddle
In the replacement use the full match $& followed by a comma.
$("input[name='masknumber']").on("input", function(){
let n = destroyMask(this.value);
this.setAttribute("data-normalized", n);
this.value = createMask(n);
})
function createMask(string){
return string.replace(/^(?:\w{3},)*\w{3}(?=\w)/g,"$&,");
}
function destroyMask(string){
return string.replace(/[^0-9A-Z,]/ig,'');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" name="masknumber" data-normalized="" size=64>
Or fiddle demo with a variant with 2 capture groups.

Test if a sentence is matching a text declaration using regex

I want to test if a sentence like type var1,var2,var3 is matching a text declaration or not.
So, I used the following code :
var text = "int a1,a2,a3",
reg = /int ((([a-z_A-Z]+[0-9]*),)+)$/g;
if (reg.test(text)) console.log(true);
else console.log(false)
The problem is that this regular expression returns false on text that is supposed to be true.
Could someone help me find a good regular expression matching expressions as in the example above?
You have a couple of mistekes.
As you wrote, the last coma is required at the end of the line.
I suppose you also want to match int abc123 as correct string, so you need to include letter to other characters
Avoid using capturing groups for just testing strings.
const str = 'int a1,a2,a3';
const regex = /int (?:[a-zA-Z_](?:[a-zA-Z0-9_])*(?:\,|$))+/g
console.log(regex.test(str));
You will need to add ? after the comma ,.
This token ? matches between zero and one.
Notice that the last number in your text a3 does not have , afterward.
int ((([a-z_A-Z]+[0-9]*),?)+)$

javascript regex capturing parentheses

I don't really get the concept on capturing parentheses when dealing with javascript regex. I don't understand why we need parentheses for the following example
var x = "{xxx} blah blah blah {yyy} and {111}";
x.replace( /{([^{}]*)}/g ,
function(match,content) {
console.log(match,content);
return "whatever";
});
//it will print
{xxx} xxx
{yyy} yyy
{111} 111
so when i drop the parentheses from my pattern x the results give a different value
x.replace( /{[^{}]*}/g ,
function(match,content) {
console.log(match,content);
return "whatever";
});
//it will print
{xxx} 0
{yyy} 37
{111} 49
so the content values now become numeric value which i have no idea why. Can someone explains what's going on behind the scene ?
According to the MDN documentation, the parameters to the function will be, in order:
The matched substring.
Any groups that are defined, if there are any.
The index in the original string where the match was found.
The original string.
So in the first example, content will be the string which was captured in group 1. But when you remove the group in the second example, content is actually the index where the match was found.
This is useful with replacement of texts.
For example, I have this string "one two three four" that I want to reverse like "four three two one". To achieve that I will use this line of code:
var reversed = "one two three four".replace(/(one) (two) (three) (four)/, "$4 $3 $2 $1");
Note how $n represents each word in the string.
Another example: I have the same string "one two three four" and I want to print each word twice:
var eachWordTwice = "one two three four".replace(/(one) (two) (three) (four)/, "$1 $1 $2 $2 $3 $3 $4 $4");
The numbers:
The offset of the matched substring within the total string being
examined. (For example, if the total string was "abcd", and the
matched substring was "bc", then this argument will be 1.)
Source:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
"Specifying a function as a parameter" section
Parenthesis are used to capture/replace only a portion of the match. For instance, when I use it to match phone numbers that may or may not have extensions. This function matches the whole string (if the if is correct), so the entire string is replaced, but I am only using a specific types of characters in a specific order, with whitespace or other("() -x") characters allowed in the input.
It will always output a string formatted to (651) 258-9631 x1234 if given 6512589631x1234 or 1 651 258 9631 1234. It also doesn't allow (or in this case format) toll-free numbers as they aren't allowed in my field.
function phoneNumber(v) {
// take in a string, return a formatted string (651) 651-6511 x1234
if (v.search(/^[1]{0,1}[-(\s.]{0,1}(?!800|888|877|866|855|900)([2-9][0-9]{2})[-)\s.]{0,2}([2-9][0-9]{2})[-.\s]{0,2}([0-9]{4})[\s]*[x]{0,1}([0-9]{1,5}){1}$/gi) !== -1) {return v.replace(/^[1]{0,1}[-(\s.]{0,1}(?!800|888|877|866|855|900)([2-9][0-9]{2})[-)\s.]{0,2}([2-9][0-9]{2})[-.\s]{0,2}([0-9]{4})[\s]*[x]{0,1}([0-9]{1,5}){1}$/gi,"($1) $2-$3 x$4"); }
if (v.search(/^[1]{0,1}[-(\s.]{0,1}(?!800|888|877|866|855|900)([2-9][0-9]{2})[-)\s.]{0,1}([2-9][0-9]{2})[-.\s]{0,2}([0-9]{4})$/gi) !== -1) { return v.replace(/^[1]{0,1}[-(\s.]{0,1}(?!800|888|877|866|855|900)([2-9][0-9]{2})[-)\s.]{0,1}([2-9][0-9]{2})[-.\s]{0,2}([0-9]{4})$/gi,"($1) $2-$3"); }
return v;
}
What this allows me to do is gather the area code, prefix, line number, and an optional extension, and format it the way I need it (for users who can't follow directions, for instance).
So it you input 6516516511x1234 or "(651) 651-6511 x1234", it will match one regex or another in this example.
Now what is happening in your code is as #amine-hajyoussef said - The index of the start of each match is being returned. Your use of that code would be better serviced by match for example one (text returned), or search for the index, as in example two. p.s.w.g's answer expands.

what regular expression would I use to retrieve the digits that follow this string?

I'm using jQuery to retrieve the class attribute and I need to get the a substring of the digits that follow the substring "position"
for example
"position7 selected" I need to retrieve "7"
for example
"navitem position14 selected" I need to retrieve "14"
I started writing:
$(this).attr('class').match(/(\d+)$/))
But I am getting lost with the regular expression, any help much appreciated.
I actually really really like regular expressions but I'm still learning!
update due to first answer: there might be another group of digits which I need to ignore
For example "navitem2 position14 selected" I need to retrieve "14"
"navitem position14 selected".match(/position(\d+)/)[1]
The call returns ["position14", "14"], so the [1] element is 14.
You're on the right track with the (\d+), it will match a contiguous group of digits. This just says only match that group when it directly follows the literal string "position".
Your attempt has two problems. The first is you anchor it to the end of the string with $. So instead of giving you the digits after position it will give you digits at the endof the string. At the same time you don't mention position at all. What you are looking for is this:
var matches = str.match(/position(\d+)/);
Now matches will be
["position14", "14"]
You can replace everything that is not a number
str.replace(/\D/g,"");
If other numbers are present in the string you can still use replace
str.replace(/^.*position(\d+).*$/,"$1");
However, you may want to go for one of the other regex expressions in the other answers.
var r = "aaa 1 bb 2 position 113 dd".match(/position\s*(\d+)/)
if (r instanceof Array )
return r.pop()

Javascript (node) regex doesn't seem to match start of string

im struggling with regular expressions in Javascript, they don't seem to start at the beginning of the string. In a simple example bellow I want to get the file name and then everything after the first colon
//string
file.text:16: lots of random text here with goes on for ages
//regex
(.?)[:](.*)
// group 1 returns 't'
/^([^:]+):(.*)/.exec('file.text:16: lots of random text here with goes on for ages')
gives ....
["file.text:16: lots of random text here with goes on for ages", "file.text", "16: lots of random text here with goes on for ages"]
Try this regex:
/^([^:]+)[:](.*)/
Explaination:
^ #Start of string
( #Start of capturing class #1
[^:] #Any character other than :
+ #One or more of the previous character class
) #End of capturing class #1
[:] #One :
(.*) #Any number of characters other than newline
The ? operator captures zero or one of the previous symbol only.
You could also use string operations instead:
str = "file.text:16:";
var n = str.indexOf(":");
var fileName = str.substr(0, n);
var everythingElse = str.substr(n);
The ? operator returns 0 or 1 matches. You want the * operator, and you should select everything that isn't a : in the first set
([^:]*)[:](.*)
Non-regexy answer:
var a = s.split(":");
Then join a[1] and remaining elements.
Or just get the index of the first semicolon and create two strings using that.

Categories

Resources