I have situation where I have to split the string in to 3 substrings.
Example
<=Mindate+30 >>> [<=,Mindate,+30]
<=Mindate >>> [<=,Mindate]
>=Maxdate-3 >>> [>=,Maxdate,-3]
==Date >>> [==,Date]
I have created a function that split current array in two
function splitString(str){
var a= /(>=|<=|=|<|>|\!=)|.+/g
return str.match(a);
}
splitString('<=Mindate+45');
Current output ['<=', 'Mindate+45']
Expected output ['<=', 'Mindate', '+45']
Can any one help me on this ?
You just needed to separate the textual part (\w+) from the number part ([-+]\d+):
function splitToThree(input) {
let regex = /(>=|<=|==|<|>|\!=)|\w+|[-+]\d+/g;
let ans = input.match(regex);
console.log(ans);
}
splitToThree("<=Mindate+30");
splitToThree("<=Mindate");
splitToThree(">=Maxdate-3");
splitToThree("==Date");
You can create a pattern that matches and captures all the comparison operators or matches a place before each of the +, /, * and - operators, and use the expression inside a String#split method:
a.split(/([<>!=]=|[=<>])|(?=[-+\/*])/).filter(Boolean)
See the JS demo:
var strs = ['<=Mindate+30', '<=Mindate','>=Maxdate-3','==Date','>=SomeFn-3.45'];
rx = /([<>!=]=|[=<>])|(?=[-+\/*])/;
for (var a of strs) {
var res = a.split(rx).filter(Boolean);
console.log(a, "=>", res);
}
Pattern details
([<>!=]=|[=<>]) - Group 1 (this value will be part of the resulting array): <, >, !, = followed with = or a =, < or > char
| - or
(?=[-+\/*]) - a location that is followed with -, +, / or *.
Note: .filter(Boolean) will remove empty items from the resulting array.
Related
I'm trying to create a regex that will select the numbers/numbers with commas(if easier, can trim commas later) that do not have a parentheses after and not the numbers inside the parentheses should not be selected either.
Used with the JavaScript's String.match method
Example strings
9(296,178),5,3(123),10
10,9(296,178),2,5,3(123),3(124,125)
10,7,5(296,293,444,1255),3(218),2,4
What i have so far:
/((^\d+[^\(])|(,\d+,)|(,*\d+$))/gm
I tried this in regex101 and underlined the numbers i would like to match and x on the one that should not.
You could start with a substitution to remove all the unwanted parts:
/\d*\(.*?\),?//gm
Demo
This leaves you with
5,10
10,2,5,
10,7,2,4
which makes the matching pretty straight forward:
/(\d+)/gm
If you want it as a single match expression you could use a negative lookbehind:
/(?<!\([\d,]*)(\d+)(?:,|$)/gm
Demo - and here's the same matching expression as a runnable javascript (skeleton code borrowed from Wiktor's answer):
const text = `9(296,178),5,3(123),10
10,9(296,178),2,5,3(123),3(124,125)
10,7,5(296,293,444,1255),3(218),2,4`;
const matches = Array.from(text.matchAll(/(?<!\([\d,]*)(\d+)(?:,|$)/gm), x=>x[1])
console.log(matches);
Here, I'd recommend the so-called "best regex trick ever": just match what you do not need (negative contexts) and then match and capture what you need, and grab the captured items only.
If you want to match integer numbers that are not matched with \d+\([^()]*\) pattern (a number followed with a parenthetical substring), you can match this pattern or match and capture the \d+, one or more digit matching pattern, and then simply grab Group 1 values from matches:
const text = `9(296,178),5,3(123),10
10,9(296,178),2,5,3(123),3(124,125)
10,7,5(296,293,444,1255),3(218),2,4`;
const matches = Array.from(text.matchAll(/\d+\([^()]*\)|(\d+)/g), x=> x[1] ?? "").filter(Boolean)
console.log(matches);
Details:
text.matchAll(/\d+\([^()]*\)|(\d+)/g) - matches one or more digits (\d+) + ( (with \() + any zero or more chars other than ( and ) (with [^()]*) + \) (see \)), or (|) one or more digits captured into Group 1 ((\d+))
Array.from(..., x=> x[1] ?? "") - gets Group 1 value, or, if not assigned, just adds an empty string
.filter(Boolean) - removes empty strings.
Using several replacement regexes
var textA = `9(296,178),5,3(123),10
10,9(296,178),2,5,3(123),3(124,125)
10,7,5(296,293,444,1255),3(218),2,4
`
console.log('A', textA)
var textB = textA.replace(/\(.*?\),?/g, ';')
console.log('B', textB)
var textC = textB.replace(/^\d+|\d+$|\d*;\d*/gm, '')
console.log('C', textC)
var textD = textC.replace(/,+/g, ' ').trim(',')
console.log('D', textD)
With a loop
Here is a solution which splits the lines on comma and loops over the pieces:
var inside = false;
var result = [];
`9(296,178),5,3(123),10
10,9(296,178),2,5,3(123),3(124,125)
10,7,5(296,293,444,1255),3(218),2,4
`.split("\n").map(line => {
let pieceArray = line.split(",")
pieceArray.forEach((piece, k) => {
if (piece.includes('(')) {
inside = true
} else if (piece.includes(')')) {
inside = false
} else if (!inside && k > 0 && k < pieceArray.length-1 && !pieceArray[k-1].includes(')')) {
result.push(piece)
}
})
})
console.log(result)
It does print the expected result: ["5", "7"]
I'm trying to write a regex function that return all of the digits in a comma separated string:
function printDigits() {
var result = sentence.replace(/[^0-9]/g, '').split(",")
console.log(result)
}
But it just prints out a string instead of digits being separated by comma. Are there any ways I can fix this?
Input: "5om3 wr173 w0rd5 u51n9 numb3r5."
Expected output: "5,3,1,7,3,0,5,5,1,9,3,5"
split doesn't work this way. It splits by the separator that is already in the input. To split string to individual characters use split(''), and then join individual characters with comma:
var result = sentence.replace(/[^0-9]/g, '').split('').join(',');
You can use
sentence.match(/\d/g).join(",")
Here,
sentence.match(/\d/g) - extracts each separate digit from string
.join(",") - join the array items into a single comma-delimited string.
See the JavaScript demo:
var sentence = "5om3 wr173 w0rd5 u51n9 numb3r5.";
console.log(sentence.match(/\d/g).join(","));
// -> 5,3,1,7,3,0,5,5,1,9,3,5
Here's another variation that uses pure regex and does not require a .join() call:
sentence.replace(/\D+|(\d)(?=\d)/g, '$1,');
This replaces any string of non-digit characters with a comma. And it also locates the position between two digits and adds a comma between them.
Pattern breakdown:
\D+ - Match one or more non-digit characters.
| - OR...
(\d) - Match one digit and capture it in group 1.
(?=\d) - Followed by another digit.
Substition:
$1, - Replace with whatever was captured in group 1, plus a comma.
Here's a full demo:
var sentence = "5om3 wr173 w0rd5 u51n9 numb3r5";
var result = sentence.replace(/\D+|(\d)(?=\d)/g, '$1,');
console.log(result); // 5,3,1,7,3,0,5,5,1,9,3,5
A reducer solution
const x = `5om3 wr173 w0rd5 u51n9 numb3r5`
.split('')
.reduce((acc, val) =>
val.trim().length && !isNaN(+val) ? [...acc, +val] : acc, []);
console.log(`${x}`);
Or simply
console.log(`${`5om3 wr173 w0rd5 u51n9 numb3r5`.match(/\d/g)}`);
Sorry if the wording is bad. So I'm trying to find out how to pass in a string match of multiple characters long into my dynamic regex expression.
The regex in my else statement works with 1 character being passed in so I'm trying to do the same thing except with multiple characters being passed in the first if statement.
const delimiter = str.slice(0, str.indexOf('\n'));
const strLength = delimiter.length;
if (delimiter[0] === '[' && delimiter.charAt(strLength - 1) === ']') {
const customDelimiter = delimiter.slice(delimiter.indexOf(delimiter[1]), delimiter.indexOf(delimiter.charAt(strLength - 1)));
console.log(customDelimiter) // => '***'
const regex = new RegExp(`,|\\n|\\${customDelimiter}`,'g');
return strArr = str.split(regex).filter(Boolean);
} else {
const firstChar = str.slice(0, 1); // => '*'
const regex = new RegExp(`,|\\n|\\${firstChar}`,'g');
return strArr = str.split(regex).filter(Boolean);
}
So for example I want this string:
'[*]\n11***22***33' to equal 66 b/c it should split it into an array of [11, 22, 33] using the '*' delimiter. I get an error message saying: "SyntaxError: Invalid regular expression: /,|\n|***/: Nothing to repeat".
When you use * as delimeter in your regex, it becomes ,|\\n|\\|\*, which is the correct regex.
It matches ',' or '\n' or a '*' character.
For your string, it matches [***]\n11***22***33.
But when you use *** as a delimiter in your regex, it becomes ,|\\n|\\|\***, which is incorrect. Here it gets two unescaped * at the end. * in regex means 0 or more of the preceding pattern. You cannot have two of them together.
This is a special case because * has a special meaning in regex.
If you would have used any non-regex character, it would work.
A simpler solution would be to use javascript split function to easily get the desired result.
You could first split the string using \n.
let splitStr = str.split('\n');
// This would return ["[***]", "11***22***33"]
and then split the 1st index of the splitStr using the delimeter.
splitStr[1].split('***');
// splitStr[1].split(customDelimiter)
// This would return ["11", "22", "33"]
Using this you wouldn't need to use if or else statement to separate out single character delimiter and multiple character delimiter.
I wanted to strictly match the strings like 45% or 2%.
It should not match if there are other strings added before or after the required string like abc34% or 34%cd212.
This will work for you:
const testData = (data) => /^(?:[1-9]\d?%|0%)$/.test(data)
const test = ["1.2%","120%","12%","2%", "ABc%", "1,3%", "23", "abc34%", "34%cd212", "00%", "0%"]
for(let x of test){
console.log(`${x} ${testData(x)}`)
}
^ begining of string
[1-9] number from 1 to 9
\d? optional 1 number
% % symbol
$ end of sting
|0% or 0%
You can use the following regex:
^\d+%$
^ Start of the string. This makes sure, that the string ABC45% is not allowed.
\d+ At least one number
$ End of the string. This makes sure, that the string 45%ABC is not allowed
Here is a live example:
var regex = /^\d+%$/;
var samples = [
"123%",
"ABC12%",
"ABC123%ABC",
"123%abc",
"abc"
];
for(var i=0; i<samples.length; i++) {
var sample = samples[i];
console.log(sample, !!sample.match(regex));
}
I've have a input string:
12345,3244,654,ffgv,87676,988ff,87657
I'm having a difficulty to transform all terms in the string that are not five digit numbers to a constant 34567 using regular expressions. So, the output would be like this:
12345,34567,34567,34567,87676,34567,87657
For this, I looked at two options:
negated character class: Not useful because it does not execute directly on this expression ,[^\d{5}],
lookahead and lookbehind: Issue here is that it doesn't include non-matched part in the result of this expression ,(?!\d{5}) or (?<!\d{5}), for the purpose of substitution/replace.
Once the desired expression is found, it would give a result so that one can replace non-matched part using tagged regions like \1, \2.
Is there any mechanism in regular expression tools to achieve the output as mentioned in the above example?
Edit: I really appreciate those who have answered non-regex solutions, but I would be more thankful if you provide a regex-based solution.
You don't need regex for this. You can use str.split to split the string at commas first and then for each item check if its length is greater than or equal to 5 and it contains only digits(using str.isdigit). Lastly combine all the items using str.join.
>>> s = '12345,3244,654,ffgv,87676,988ff,87657'
>>> ','.join(x if len(x) >= 5 and x.isdigit() else '34567' for x in s.split(','))
'12345,34567,34567,34567,87676,34567,87657'
Javascript version:
function isdigit(s){
for(var i=0; i <s.length; i++){
if(!(s[i] >= '0' && s[i] <= '9')){
return false;
}
}
return true;
}
arr = "12345,3244,654,ffgv,87676,988ff,87657".split(",");
for(var i=0; i < arr.length; i++){
if(arr[i].length < 5 || ! isdigit(arr[i])) arr[i] = '34567';
}
output = arr.join(",")
Try the following: /\b(?!\d{5})[^,]+\b/g
It constrains the expression between word boundaries (\b),
Followed by a negative look-ahead for non five digit numbers (!\d{5}),
Followed by any characters between ,
const expression = /\b(?!\d{5})[^,]+\b/g;
const input = '12345,3244,654,ffgv,87676,988ff,87657';
const expectedOutput = '12345,34567,34567,34567,87676,34567,87657';
const output = input.replace(expression, '34567');
console.log(output === expectedOutput, expectedOutput, output);
This approach uses /\b(\d{5})|(\w+)\b/g:
we match on boundaries (\b)
our first capture group captures "good strings"
our looser capture group gets the leftovers (bad strings)
our replacer() function knows the difference
const str = '12345,3244,654,ffgv,87676,988ff,87657';
const STAND_IN = '34567';
const massageString = (str) => {
const pattern = /\b(\d{5})|(\w+)\b/g;
const replacer = (match, goodstring, badstring) => {
if (goodstring) {
return goodstring;
} else {
return STAND_IN;
}
}
const r = str.replace(pattern,replacer);
return r;
};
console.log( massageString(str) );
I think the following would work for value no longer than 5 alphanumeric characters:
(,(?!\d{5})\w{1,5})
if longer than 5 alphanumeric characters, then remove 5 in above expression:
(,(?!\d{5})\w{1,})
and you can replace using:
,34567
You can see a demo on regex101. Of course, there might be faster non-regex methods for specific languages as well (python, perl or JS)