Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit the character range in regular expression?

Lets say,

let sentence= "Dear user {#val#}{#val#} thanks"

{#val#} is the dynamic value in the above sentence. Here in place of {#val#}, there can be any values but atleast 0 and maximum 5 characters can be there. So I'm substituting the {#val#} as .{0,5} . I dont need to consider spaces except for the {#val#} portion, so my formed regex would be,

let regex =  /^Dear\s*user\s*.{0,5}.{0,5} thanks$/i
let customermsg = "Dear user 1 2 thanks" //Should be valid
let customermsg1 = "Dear user 12345 6789 thanks" //Should be valid
let customermsg2 = "Dear user 123 5 6789 thanks" //Should be valid because space can also be considered as a character and for fist .{0,5} => 123 5 and for second .{0,5} => 6789
let customermsg3 = "Dear user 1 thanks" //Should pass 
let customermsg4 = "Dea r user 1 tha nks" // Should Pass since spaces are not considered in the static portion.

but when I try to test using below,

 regex.test(customermsg)

Its quite opposite. Even I have tried the below,

let splitters=/{\\#val\\#}|((\\s\*))/gi;
sentence = sentence.replace(splitters, (x, y) => y ? y : ".(\\S{0,5})"); 

This returns the regex as,

 /^Dear\s*user\s*.(\S{0,5}).(\S{0,5})\s*thanks$/

But this is also not working as expected. I'm stuck on this. Please help me.

like image 483
sasi Avatar asked Feb 24 '21 10:02

sasi


People also ask

How do you limit the length of a regular expression?

By combining the interval quantifier with the surrounding start- and end-of-string anchors, the regex will fail to match if the subject text's length falls outside the desired range.

How do you specify a range in regex?

Range in Regular Expressions Ranges of characters can be indicated by giving two characters and separating them by a '-', for example [a-z] will match any lowercase ASCII letter, [0-5][0-9] will match all the two-digits numbers from 00 to 59.

What is difference [] and () in regex?

[] denotes a character class. () denotes a capturing group. [a-z0-9] -- One character that is in the range of a-z OR 0-9. (a-z0-9) -- Explicit capture of a-z0-9 .


3 Answers

What you need is to check if a number and white spaces are present multiple times according to

"Dear user 1 thanks" //Should fail since only one value is there

So, your regex is fine, except that it doesn't check if a number and white spaces are present more than one times.

Use the following regex

Dear\s*user\s*([\d]+[\s]+){2,5}\s*thanks$
  • ([\d]+[\s]+){2,5}\s*

    • Capturing group matching digit between zero and unlimited times and white space between zero and unlimited times, for atleast two times and max five.

The ([\d]+[\s]+){2,5}\s* part makes it sure that a number is present atleast two times, so a single number in the string Dear user ... thanks will fail.

You can use as many white spaces before, between and after the digits as you please.

let regex =  /Dear\s*user\s*([\d]+[\s]+){2,5}\s*thanks$/i
let customermsg = "Dear user 1 2 thanks" //Should be valid
let customermsg1 = "Dear user 12345 6789 thanks" //Should be valid
let customermsg2 = "Dear user 123 5 6789 thanks" //Should be valid because space can also be considered as a character and for fist .{1,5} => 123 5 and for second .{1,5} => 6789
let customermsg3 = "Dear user 1 thanks" //Should fail since only one value is there
let customermsg4 = "Dear user   435 4523 thanks" // With many spaces

console.log(regex.test(customermsg));
console.log(regex.test(customermsg1));
console.log(regex.test(customermsg2));
console.log(regex.test(customermsg3));
console.log(regex.test(customermsg4));
like image 107
Red Avatar answered Oct 17 '22 12:10

Red


As I understand it you want

  • Both vals to be replaced by the same regex
  • Spaces before the val to be ignored
  • Spaces to be part of the val

And also

  • val cannot start with a space

The first point is the trickiest because you need to ensure that the first value does not start with a space while the second value can, yet still be the same regex. Essentially you have two different requirements here.

The only solution I can think of is to do a lookahead to ensure that the next character after the optional spaces after user is a non-space character.

/^Dear\s*user\s*(?=\S)(.{1,5}.{1,5}) thanks$/

https://regex101.com/r/AtUxDS/2

like image 1
Khauri Avatar answered Oct 17 '22 11:10

Khauri


You could use s capture group for the part before the match, and start the match with a single non whitespace char.

Assert 1-9 chars at the right followed by thanks. If that is the case, match at least another non whitespace char followed by the rest until you reach thanks.

For example

let regex = /^(Dear\s*user\s*)\S(?=.{1,9} thanks$)\s*\S.*(?= thanks$)/i;
[
  "Dear user 1 2 thanks",
  "Dear user 12345 6789 thanks",
  "Dear user 123 5 6789 thanks",
  "Dear user 1    thanks",
  "Dear user 1 thanks"
].forEach(s =>
  console.log(s.replace(regex, (m, g1) => g1 + "{#val#}{#val#}"))
);

Or if there can be only digits and spaces with a single capture group

let regex = /^(Dear\s*user\s*)\d(?=[ \d]*\d)[ \d]{1,9}(?= thanks$)/i;
[
  "Dear user 1 2 thanks",
  "Dear user 12345 6789 thanks",
  "Dear user 123 5 6789 thanks",
  "Dear user 1 thanks",
  "Dear user 1    thanks",
  "Dear user 12345 64789 thanks"
].forEach(s =>
  console.log(s.replace(regex, (m, g1) => g1 + "{#val#}{#val#}"))
);
like image 1
The fourth bird Avatar answered Oct 17 '22 12:10

The fourth bird