I've been trying to find a way to match a number in a Javascript string that is surrounded by parenthesis at the end of the string, then increment it.
Say I have a string:
var name = "Item Name (4)";
I need a RegExp to match the (4) part, and then I need to increment the 4 then put it back into the string.
This is the regex I have so far:
\b([0-9]+)$\b
This regex does not work. Furthermore, I do not know how to extract the integer retrieved and put it back in the same location in the string.
Thanks.
The replace method can take a function as its second argument. It gets the match (including submatches) and returns the replacement string. Others have already mentioned that the parentheses need to be escaped.
"Item Name (4)".replace(/\((\d+)\)/, function(fullMatch, n) {
return "(" + (Number(n) + 1) + ")";
});
I can can only think of a way of doing it in three steps: Extract, increment and replace.
// Tested on rhino
var name = "Item Name (4)";
var re = /\((\d+)\)/;
match = re.exec(name);
number = parseInt(match[1]) + 1;
name = name.replace(re, "(" + number + ")");
The important parts of the pattern:
You need to escape the parens to match literal parens
You also need the to use parens to capture the number so that you can extract it from the match.
\d matches a digit and is shorter and more common than writing out [0-9].
In order this pattern to work you shoud escape parenthesis. In addition \b and $ are unneeded. Thus
var s = "Item Name (4)";
var match = /\((\d+)\)/.exec( s );
var n = Number(match[1])+1;
alert( s.replace( /\(\d+\)/, '('+n+')' ) );
Solution by david.clarke (tested)
"Item Name (4)".replace(/\(([0-9]+)\)/, '('+(1+RegExp.$1) + ')');
But I think it is too concise
UPD: It turned out that RegExp.$1 can't be used as part of replace parameter, because it works only in Opera
'var name = "Item Name (4)"'.replace(/\(([\d]+)\)/, 1 + $1);
(untested)
Related
I have this string:
var s = '/channels/mtb/videos?page=2&per_page=100&fields=uri%2Cname%2Cdescription%2Cduration%2Cwidth%2Cheight%2Cprivacy%2Cpictures.sizes&sort=date&direction=asc&filter=embeddable&filter_embeddable=true'
I want to repace per_page number (in this case 100, but it can be any number from 1-100, maybe more?)
I can select first part of the string with:
var s1 = s.substr(0, s.lastIndexOf('per_page=')+9)
which give me:
/channels/mtb/videos?page=2&per_page=
but how would I select next '&' after that so I can replace number occurrence?
dont assume same order of parameters!
You can use following regex to replace the content you want.
regex:- /per_page=[\d]*/g(this is only for your requirement)
var new_no=12; //change 100 to 12
var x='/channels/mtb/videos?page=2&per_page=100&fields=uri%2Cname%2Cdescription%2Cduration%2Cwidth%2Cheight%2Cprivacy%2Cpictures.sizes&sort=date&direction=asc&filter=embeddable&filter_embeddable=true';
var y=x.replace(/per_page=[\d]*/g,'per_page='+new_no);
console.log(y);
Explanation:-
/per_page=[\d]*/g
/ ----> is for regex pattern(it inform that from next character onward whatever it encounter will be regex pattern)
per_page= ----> try to find 'per_page=' in string
[\d]* ----> match 0 or more digit (it match until non digit encounter)
/g ---->/ to indicate end of regex pattern and 'g' is for global means find in all string(not only first occurrence)
Use replace with a regular expression to find the numbers after the text per_page=. Like this:
s.replace(/per_page=\d+/,"per_page=" + 33)
Replace the 33 with the number you want.
Result:
"/channels/mtb/videos?page=2&per_page=33&fields=uri%2Cname%2Cdescription%2Cduration%2Cwidth%2Cheight%2Cprivacy%2Cpictures.sizes&sort=date&direction=asc&filter=embeddable&filter_embeddable=true"
Start with the index from the lastIndexOf-per_page instead of 0.
Get the index of the first & and create a substr s2 to the end.
Then concat s1 + nr + s2.
I would not use regex, because it is much slower for this simple stuff.
With Array.filter you can do this, where one split the text into key/value pairs, and filter out the one that starts with per_page=.
Stack snippet
var s = '/channels/mtb/videos?page=2&per_page=100&fields=uri%2Cname%2Cdescription%2Cduration%2Cwidth%2Cheight%2Cprivacy%2Cpictures.sizes&sort=date&direction=asc&filter=embeddable&filter_embeddable=true'
var kv_pairs = s.split('&');
var s2 = s.replace((kv_pairs.filter(w => w.startsWith('per_page=')))[0],'per_page=' + 123);
//console.log(s2);
var matches = /(.*\bper_page=)(\d+)(.*)/;
if (matches) {
s = matches[0] + newValue + matches[2];
}
I have this line in my loop:
var regex1 = new RegExp('' + myClass + '[:*].*');
var rule1 = string.match(regex1)
Where "string" is a string of class selectors, for example: .hb-border-top:before, .hb-border-left
and "myClass" is a class: .hb-border-top
As I cycle through strings, i need to match strings that have "myClass" in them, including :before and :hover but not including things like hb-border-top2.
My idea for this regex is to match hb-border-top and then :* to match none or more colons and then the rest of the string.
I need to match:
.hb-fill-top::before
.hb-fill-top:hover::before
.hb-fill-top
.hb-fill-top:hover
but the above returns only:
.hb-fill-top::before
.hb-fill-top:hover::before
.hb-fill-top:hover
and doesn't return .hb-fill-top itself.
So, it has to match .hb-fill-top itself and then anything that follows as long as it starts with :
EDIT:
Picture below: my strings are the contents of {selectorText}.
A string is either a single class or a class with a pseudo element, or a rule with few clases in it, divided by commas.
each string that contains .hb-fill-top ONLY or .hb-fill-top: + something (hover, after, etc) has to be selected. Class is gonna be in variable "myClass" hence my issue as I can't be too precise.
I understand you want to get any CSS selector name that contains the value anywhere inside and has EITHER : and 0+ chars up to the end of string OR finish right there.
Then, to get matches for the .hb-fill-top value you need a solution like
/\.hb-fill-top(?::.*)?$/
and the following JS code to make it all work:
var key = ".hb-fill-top";
var rx = RegExp(key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + "(?::.*)?$");
var ss = ["something.hb-fill-top::before","something2.hb-fill-top:hover::before","something3.hb-fill-top",".hb-fill-top:hover",".hb-fill-top2:hover",".hb-fill-top-2:hover",".hb-fill-top-bg-br"];
var res = ss.filter(x => rx.test(x));
console.log(res);
Note that .replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') code is necessary to escape the . that is a special regex metacharacter that matches any char but a line break char. See Is there a RegExp.escape function in Javascript?.
The ^ matches the start of a string.
(?::.*)?$ will match:
(?::.*)?$ - an optional (due to the last ? quantifier that matches 1 or 0 occurrences of the quantified subpattern) sequence ((?:...)? is a non-capturing group) of a
: - a colon
.* - any 0+ chars other than line break chars
$ - end of the string.
var regex1 = new RegExp(`^\\${myClass}(:{1,2}\\w+)*$`)
var passes = [
'.hb-fill-top::before',
'.hb-fill-top:hover::before',
'.hb-fill-top',
'.hb-fill-top:hover',
'.hb-fill-top::before',
'.hb-fill-top:hover::before',
'.hb-fill-top:hover'
];
var fails = ['.hb-fill-top-bg-br'];
var myClass = '.hb-fill-top';
var regex = new RegExp(`^\\${myClass}(:{1,2}\\w+)*$`);
passes.forEach(p => console.log(regex.test(p)));
console.log('---');
fails.forEach(f => console.log(regex.test(f)));
var regex1 = new RegExp('\\' + myClass + '(?::[^\s]*)?');
var rule1 = string.match(regex1)
This regex select my class, and everething after if it start with : and stop when it meets a whitespace character.
See the regex in action.
Notice also that I added '\\' at the beginning. This is in order to escape the dot in your className. Otherwise it would have matched something else like
ahb-fill-top
.some-other-hb-fill-top
Also be careful about .* it may match something else after (I don't know your set of strings). You might want to be more precise with :{1,2}[\w-()]+ in the last group. So:
var regex1 = new RegExp('\\' + myClass + '(?::{1,2}[\w-()]+)?');
I have the following input fields with name attributes of:
carousels['components'][0][0][title]
carousels['components'][0][1][title]
carousels['components'][0][2][title]
carousels['components'][1][0][title]
carousels['components'][1][1][title]
carousels['components'][1][2][title]
carousels['components'][2][0][title]
carousels['components'][2][1][title]
carousels['components'][2][2][title]
I am trying to match the final [ number ] eg this part:
carousels['components'][2][THIS][title]
carousels['components'][2][THIS][title]
carousels['components'][2][THIS][title]
While ignoring the rest
Here is my regex pattern:
/(\[[^components\]])+(\[*])/
This affects both of the int's within brackets when I just want the last one. This regex also doesn't recognize the specific requirement of the first array key 'component'
Live regex test here:
http://www.regexpal.com/?fam=94974
If you want to get the last [ + digits + ], you can use
/^.*\[(\d+)\].*$/
See the regex demo
Backtracking will help getting exactly the last occurrence of [digits]. Grab Group 1 value.
var re = /^.*\[(\d+)\].*$/;
var str = 'carousels[\'components\'][0][0][title]\ncarousels[\'components\'][0][1][title]\ncarousels[\'components\'][0][2][title]\n\ncarousels[\'components\'][1][0][title]\ncarousels[\'components\'][1][1][title]\ncarousels[\'components\'][1][2][title]\n\ncarousels[\'components\'][2][0][title]\ncarousels[\'components\'][2][1][title]\ncarousels[\'components\'][2][2][title]';
for (var s of str.split("\n")) {
var res = (m=re.exec(s)) ? m[1] : "";
if (res) {
document.body.innerHTML += s + ": " + res + "<br/>";
}
}
UPDATE:
To get the first [ + digits + ], you need to use lazy matching with the first dot:
/^.*?\[(\d+)\].*$/
^ - Here, the ? will make matching lazy/reluctant
(it will match any 0+ chars other than a newline as few as possible)
See another regex demo.
You can try this
^.*(\[.*?\])\[.*?\]$
<------->
Match in this(1st captured group)
Regex Demo
If you want to match ['components'] exclusively, then you can use
^.*\['components'\].*(\[.*?\])\[.*?\]$
Im using an API call to populate some fields on my website. These fields are populated with different parts of an address. However, in my first address line field the value is abbreviated. For example, if i had 'Smith Street' it would get inserted as 'Smith St'. To get around this issue i am using javascript to replace the value, for example:
value = value.replace("St", "Street");
However if i then have, for example, a value that is 'Stanley Street' it would return 'Streetanley Street'.
Does anybody know of a method i can use to apply the replace method to the last word in a string?
You're looking for a regular expression. Get used to them, if you plan on writing much JavaScript.
value = value.replace(/St$/, "Street");
will replace "St" only if it's the end of the string. ($ matches end-of-string)
If we wanted to allow for white space at the end of the string, and still replace, we would say:
value = value.replace(/St\s*$/, "Street");
Where \s means "any white space character" and * means "0 or more times".
And if we want to match both "St" and "St.", we'd say:
value = value.replace(/St\.?\s*$/, "Street");
where \. is just a ".", and ? means "at most once".
To avoid replacing "st" in the middle of a word, use a word boundary (\b):
value = value.replace(/\bSt\.?\s*$/, "Street");
And you probably want to use a case-insensitive match (/i), so "Main st" is converted just as well as "Main Street":
value = value.replace(/\bSt\.?\s*$/i, "Street");
value = value.replace(/(\s)St(\S*)$/, "$1Street$2");
/\sSt\S*$/ will match last word if it is beggining with St (\s - whitespace character, then goes St and then \S - not whitespace character * many times, and then goes $ - end of string).
Then you need to wrap with () any parts you will need to re-use and then re-use them with $1 $2 etc
You can use a boundary across your word. To create a boundary wrap your word in
/\bYourWord or words\b/g
value.replace(/\bSt\b/g, "Street");
You can use the word boundary expression: \b
var abbreviations= {
"st":"street",
"av":"avenue"
//...
};
for( var i in abbreviations ){
str= str.replace( new RegExp( "\\b" + i + "\\b" ,"i" ) , abbreviations[i] );
}
document.querySelector("input").addEventListener("input",function(evt){
document.querySelector("#output").innerHTML= correctAbbreviations(evt.target.value);
});
function correctAbbreviations(str){
var abbreviations= {
"st":"street",
"av":"avenue"
//...
};
for( var i in abbreviations ){
str= str.replace( new RegExp( "\\b" + i + "\\b" ,"i" ) , abbreviations[i] );
}
return str;
};
#output{
background:#ddd;
width:auto;
}
<input type="text" >
<br/><span id="output"></span>
I'm trying to split a string into an array based on the second occurrence of the symbol _
var string = "this_is_my_string";
I want to split the string after the second underscore. The string is not always the same but it always has 2 or more underscores in it. I always need it split on the second underscore.
In the example string above I would need it to be split like this.
var split = [this_is, _my_string];
var string = "this_is_my_string";
var firstUnderscore = string.indexOf('_');
var secondUnderscore = string.indexOf('_', firstUnderscore + 1);
var split = [string.substring(0, secondUnderscore),
string.substring(secondUnderscore)];
Paste it into your browser's console to try it out. No need for a jsFiddle.
var string = "this_is_my_string";
var splitChar = string.indexOf('_', string.indexOf('_') + 1);
var result = [string.substring(0, splitChar),
string.substring(splitChar, string.length)];
This should work.
var str = "this_is_my_string";
var matches = str.match(/(.*?_.*?)(_.*)/); // MAGIC HAPPENS HERE
var firstPart = matches[1]; // this_is
var secondPart = matches[2]; // _my_string
This uses regular expressions to find the first two underscores, and captures the part up to it and the part after it. The first subexpression, (.*?_.*?), says "any number of characters, an underscore, and again any number of characters, keeping the number of characters matched as small as possible, and capture it". The second one, (_.*) means "match an underscore, then any number of characters, as much of them as possible, and capture it". The result of the match function is an array starting with the full matched region, followed by the two captured groups.
I know this post is quite old... but couldn't help but notice that no one provided a working solution. Here's one that works:
String str = "this_is_my_string";
String undScore1 = str.split("_")[0];
String undScore2 = str.split("_")[1];
String bothUndScores = undScore1 + "_" + undScore2 + "_";
String allElse = str.split(bothUndScores)[1];
System.out.println(allElse);
This is assuming you know there will always be at least 2 underscores - "allElse" returns everything after the second occurrence.