I have a number like this.
const number = 123456789;
I'd like to split it like [1, 2345, 6789] or ['1','2345','6789'];
I've found match() with Regex.
console.log(number.toString().match(/.{1,4}/g));
It returns ['1234', '5678', '9']
It looks pretty well done, but It's a reversed result that I want.
so, I made a tricky flow for this.
console.log(number.toString().split('').reverse().join('').match(/.{1,4}/g));
So, Now I get ['9876','5432','1']
But it doesn't still being what I want.
console.log(
number.toString().split('').reverse().join('').match(/.{1,4}/g).map(str=>str.split('').reverse().join('')).reverse());
Finally, I can get the result that I want.
But It looks pretty ugly and inefficient.
Even I think it shouldn't be used on the code.
So, my question is How can I split a number every nth position efficiently?
If you want to make the code shorter, match 1 to 4 characters while using negative lookahead for 0 or more groups of .{4}, followed by $ (the end of the string):
const number = 123456789;
console.log(
number.toString().match(/.{1,4}(?=(?:.{4})*$)/g)
);
But this requires, on every match, checking the number of characters from the match to the end of the string, which is an O(n ^ 2) process overall. To be more efficient, check the length of the string first, and use modulo to take as many characters as needed to make the remaining string have a length of a multiple of 4:
const str = String(123456789);
const index = str.length % 4;
const firstItem = str.slice(0, index);
const items = str.slice(index).match(/\d{4}/g);
items.unshift(firstItem);
console.log(items);
This code is longer, but it runs in O(n).
You could match by groups from 1 to 4 characters and take look forward to a group of four.
var number = 123456789,
parts = number.toString().match(/.{1,4}(?=(.{4})*$)/g);
console.log(parts);
To avoid splitting and reversing, another option might be to left-pad the number string until it is a multiple of the group size, match and trim back again:
>>> s.padStart(s.length + (4 - s.length % 4)).match(/(.{4})/g).map(s => s.trim())
[ '1', '2345', '6789' ]
Related
I need to use (substring method) in my javascript web network project, but excluding : colon symbol, because it is hexadecimal ip address, and I don't want to accept : colons as a string or lets say number in the substring, I want to ignore it. How to do that?
This is the example IPV6 in the input field:
2001:2eb8:0dc1:54ed:0000:0000:0000:0f31
after substring from 1 to 12:
001:2eb8:0d
as you can see it accepted colons also, but in fact, I need this result:
2001:2eb8:0dc1
so by excluding these two symbols, it would have gave me that result above, but I don't know how.
and here is the code, IpAddressInput, is only a normal input field which I write the ip address in it.
Here is the code:
var IpValue = $('#IpAddressInput').val();
alert(IpValue.substr(1, (12) -1));
Answer 1: I think there is no direct function to results like you want but this answer will help you. I counted the number of colons from index 0 to 12 and then slice the source string from 0 to 12 plus the number. Here is the code:
let val = "2001:2eb8:0dc1:54ed:0000:0000:0000:0f31";
let numOfColons = val.slice(0, 12).match(/:/g).length;
let result = val.slice(0, 12 + numOfColons);
console.log(result)
Answer 2: If you are sure that there is a colon after exactly every 4 characters, a better solution will be this. The idea is to remove all colons from the string, slice from index 0 to 12, and add a colon after every 4 characters. Finally, it removes the last colon. Here is the code:
let value = "2001:2eb8:0dc1:54ed:0000:0000:0000:0f31";
let valueExcludeColon = value.replace(/:/g, ''); // '20012eb80dc154ed0000000000000f31'
let result = valueExcludeColon.slice(0,12).replace(/(.{4})/g, "$1:"); // '2001:2eb8:0dc1:'
let finalResult = result.slice(0, -1); // 2001:2eb8:0dc1
console.log(finalResult)
I would like to split a word by numbers, but at the same time keep the numbers in node.js.
For example, take this following sentence:
var a = "shuan3jia4";
What I want is:
"shuan3 jia4"
However, if you use a regexp's split() function, the numbers that are used on the function are gone, for example:
s.split(/[0-9]/)
The result is:
[ 'shuan', 'jia', '' ]
So is there any way to keep the numbers that are used on the split?
You can use match to actually split it per your requirement:
var a = "shuan3jia4";
console.log(a.match(/[a-z]+[0-9]/ig));
use parenthesis around the match you wanna keep
see further details at Javascript and regex: split string and keep the separator
var s = "shuan3jia4";
var arr = s.split(/([0-9])/);
console.log(arr);
var s = "shuan3jia4";
var arr = s.split(/(?<=[0-9])/);
console.log(arr);
This will work as per your requirements. This answer was curated from #arhak and C# split string but keep split chars / separators
As #codybartfast said, (?<=PATTERN) is positive look-behind for PATTERN. It should match at any place where the preceding text fits PATTERN so there should be a match (and a split) after each occurrence of any of the characters.
Split, map, join, trim.
const a = 'shuan3jia4';
const splitUp = a.split('').map(function(char) {
if (parseInt(char)) return `${char} `;
return char;
});
const joined = splitUp.join('').trim();
console.log(joined);
How would you change this:
a-10-b-19-c
into something like this:
a-10-b-20-c
using regular expressions in Javascript?
It should also change this:
a-10-b-19
into this:
a-10-b-20
The only solution I've found so far is:
reverse the original string -> "c-91-b-01-a"
find the first number (with \d+) -> "91"
reverse it -> "19"
turn in into a number (parseInt) -> 19
add 1 to it -> 20
turn it into a string again (toString) -> "20"
reverse it again -> "02"
replace the original match with this new number -> "c-02-b-01-a"
reverse the string -> "a-10-b-20-c"
I was hoping someone on SO would have a simpler way to do this... Anyone?
Here is a simple way.
var str = 'a-10-b-19-c';
str = str.replace(/(\d*)(?=(\D*)?$)/, +str.match(/(\d*)(?=(\D*)?$)/)[0]+1);
+str.match finds 19, adds 1 to it and returns 20. The + makes sure the answer is an int. str.replace finds 19 and replaces it with what str.match returned which was 20.
Explanation
(\d*) - matches any digits
(?=...) - positive lookahead, doesn't change regex position, but makes sure that pattern exists further on down the line.
(\D*)?$ - it doesn't have to, but can match anything that is not a number multiple times and then matches the end of the string
//replaces last digit sequences with 20
'a-10-b-19-c'.replace(/\d+(?!.*\d+)/, '20')
/ --> Start of regex
\d+ --> Match any digit (one or more)
(?!.*\d+) --> negative look ahead assertion that we cannot find any future (one or more) digits
/ --> end of regex
Edit: Just reread about adding,
Can use match for that, e.g.:
var m ='a-10-b-19-c'.match(/\d+(?!.*\d+)/);
'a-10-b-19-c'.replace(/\d+(?!.*\d+)/, parseInt(m[0]) + 1);
Here's an even simpler one:
str.replace(/(.*\D)(\d+)/, function(s, pfx, n) {return pfx + ((+n) + 1)})
or
str.replace(/.*\D(\d+)/, function(s, n) {return s.slice(0, -n.length) + ((+n) + 1)})
Neither of these will work if the number is the first thing in the string, but this one will:
(' ' + str).replace(/.*\D(\d+)/,
function(s, n) {
return s.slice(1, -n.length) + ((+n) + 1)
})
(Why does Javascript need three different substring functions?)
Here's the simplest way I can think of:
var str = 'a-10-b-19-c';
var arr = str.split('-');
arr[3] = parseInt(arr[3]) + 1;
str = arr.join('-');
Edit to explain:
The split() method takes the parameter (in this case the hyphen) and breaks it up into an array at each instance it finds. If you type arr into your JavaScript console after this part runs you'll get ["a", "10", "b", "19", "c"]
We know that we need to change the 4th item here, which is accessed by index 3 via arr[3]. Each piece of this array is a string. If you try to increment a string by 1 it will simply concatenate the string with a 1 (JS uses the + for addition and concatenation) so you need to use parseInt() to make it an integer before you do the addition.
Then we use the join() method to glue the array back together into a string!
Try this one:
var str='a-10-b-19-c';
var pattern=/\d+/g;
var matches=pattern.exec(str);
var last=matches[0];
while((matches=pattern.exec(str))!=null)
{
last=matches[0];
}
var newStr=str.replace(last, parseInt(last)+1);
console.log(newStr);
The code outputs a-10-b-20-c
have a regex problem :(
what i would like to do is to find out the contents between two or more numbers.
var string = "90+*-+80-+/*70"
im trying to edit the symbols in between so it only shows up the last symbol and not the ones before it. so trying to get the above variable to be turned into 90+80*70. although this is just an example i have no idea how to do this. the length of the numbers, how many "sets" of numbers and the length of the symbols in between could be anything.
many thanks,
Steve,
The trick is in matching '90+-+' and '80-+/' seperately, and selecting only the number and the last constant.
The expression for finding the a number followed by 1 or more non-numbers would be
\d+[^\d]+
To select the number and the last non-number, add parens:
(\d+)[^\d]*([^\d])
Finally add a /g to repeat the procedure for each match, and replace it with the 2 matched groups for each match:
js> '90+*-+80-+/*70'.replace(/(\d+)[^\d]*([^\d])/g, '$1$2');
90+80*70
js>
Or you can use lookahead assertion and simply remove all non-numerical characters which are not last: "90+*-+80-+/*70".replace(/[^0-9]+(?=[^0-9])/g,'');
You can use a regular expression to match the non-digits and a callback function to process the match and decide what to replace:
var test = "90+*-+80-+/*70";
var out = test.replace(/[^\d]+/g, function(str) {
return(str.substr(-1));
})
alert(out);
See it work here: http://jsfiddle.net/jfriend00/Tncya/
This works by using a regular expression to match sequences of non-digits and then replacing that sequence of non-digits with the last character in the matched sequence.
i would use this tutorial, first, then review this for javascript-specific regex questions.
This should do it -
var string = "90+*-+80-+/*70"
var result = '';
var arr = string.split(/(\d+)/)
for (i = 0; i < arr.length; i++) {
if (!isNaN(arr[i])) result = result + arr[i];
else result = result + arr[i].slice(arr[i].length - 1, arr[i].length);
}
alert(result);
Working demo - http://jsfiddle.net/ipr101/SA2pR/
Similar to #Arnout Engelen
var string = "90+*-+80-+/*70";
string = string.replace(/(\d+)[^\d]*([^\d])(?=\d+)/g, '$1$2');
This was my first thinking of how the RegEx should perform, it also looks ahead to make sure the non-digit pattern is followed by another digit, which is what the question asked for (between two numbers)
Similar to #jfriend00
var string = "90+*-+80-+/*70";
string = string.replace( /(\d+?)([^\d]+?)(?=\d+)/g
, function(){
return arguments[1] + arguments[2].substr(-1);
});
Instead of only matching on non-digits, it matches on non-digits between two numbers, which is what the question asked
Why would this be any better?
If your equation was embedded in a paragraph or string of text. Like:
This is a test where I want to clean up something like 90+*-+80-+/*70 and don't want to scrap the whole paragraph.
Result (Expected) :
This is a test where I want to clean up something like 90+80*70 and don't want to scrap the whole paragraph.
Why would this not be any better?
There is more pattern matching, which makes it theoretically slower (negligible)
It would fail if your paragraph had embedded numbers. Like:
This is a paragraph where Sally bought 4 eggs from the supermarket, but only 3 of them made it back in one piece.
Result (Unexpected):
This is a paragraph where Sally bought 4 3 of them made it back in one piece.
I'm trying to split up a nucleotide sequence into amino acid strings using a regular expression. I have to start a new string at each occurrence of the string "ATG", but I don't want to actually stop the first match at the "ATG". Valid input is any ordering of a string of As, Cs, Gs, and Ts.
For example, given the input string: ATGAACATAGGACATGAGGAGTCA
I should get two strings: ATGAACATAGGACATGAGGAGTCA (the whole thing) and ATGAGGAGTCA (the first match of "ATG" onward). A string that contains "ATG" n times should result in n results.
I thought the expression /(?:[ACGT]*)(ATG)[ACGT]*/g would work, but it doesn't. If this can't be done with a regexp it's easy enough to just write out the code for, but I always prefer an elegant solution if one is available.
If you really want to use regular expressions, try this:
var str = "ATGAACATAGGACATGAGGAGTCA",
re = /ATG.*/g, match, matches=[];
while ((match = re.exec(str)) !== null) {
matches.push(match);
re.lastIndex = match.index + 3;
}
But be careful with exec and changing the index. You can easily make it an infinite loop.
Otherwise you could use indexOf to find the indices and substr to get the substrings:
var str = "ATGAACATAGGACATGAGGAGTCA",
offset=0, match=str, matches=[];
while ((offset = match.indexOf("ATG", offset)) > -1) {
match = match.substr(offset);
matches.push(match);
offset += 3;
}
I think you want is
var subStrings = inputString.split('ATG');
KISS :)
Splitting a string before each occurrence of ATG is simple, just use
result = subject.split(/(?=ATG)/i);
(?=ATG) is a positive lookahead assertion, meaning "Assert that you can match ATG starting at the current position in the string".
This will split GGGATGTTTATGGGGATGCCC into GGG, ATGTTT, ATGGGG and ATGCCC.
So now you have an array of (in this case four) strings. I would now go and take those, discard the first one (this one will never contain nor start with ATG) and then join the strings no. 2 + ... + n, then 3 + ... + n etc. until you have exhausted the list.
Of course, this regex doesn't do any validation as to whether the string only contains ACGT characters as it only matches positions between characters, so that should be done before, i. e. that the input string matches /^[ACGT]*$/i.
Since you want to capture from every "ATG" to the end split isn't right for you. You can, however, use replace, and abuse the callback function:
var matches = [];
seq.replace(/atg/gi, function(m, pos){ matches.push(seq.substr(pos)); });
This isn't with regex, and I don't know if this is what you consider "elegant," but...
var sequence = 'ATGAACATAGGACATGAGGAGTCA';
var matches = [];
do {
matches.push('ATG' + (sequence = sequence.slice(sequence.indexOf('ATG') + 3)));
} while (sequence.indexOf('ATG') > 0);
I'm not completely sure if this is what you're looking for. For example, with an input string of ATGabcdefghijATGklmnoATGpqrs, this returns ATGabcdefghijATGklmnoATGpqrs, ATGklmnoATGpqrs, and ATGpqrs.