3

I have several strings like

enter image description here

I need to match the strings that start wih >=100 and <=300 folowed by space and then any string.

The expected result is

enter image description here

I have tried with

[123][0-9][0-9]\s.*

But this matched incorrectly giving 301, 399 and so on. How do I correct it?

Code Guy
  • 3,059
  • 2
  • 30
  • 74
  • 1
    Regex is not a good option for mathematical comparison. I would suggest extracting the number and checking the range properly – Phil Jun 09 '21 at 06:06

2 Answers2

6

If you're absolutely set on a regex solution, try looking for 100 - 299 or 300

const rx = /^([12][0-9]{2}|300)\s./
//          | |   |       | |  | |
//          | |   |       | |  | Any character
//          | |   |       | |  A whitespace character
//          | |   |       | Literal "300"
//          | |   |       or
//          | |   0-9 repeated twice
//          | "1" or "2"
//          Start of string

You can then use this to filter your strings with a test

const strings = [
  "99 Apple",
  "100 banana",
  "101 pears",
  "200 wheat",
  "220 rice",
  "300 corn",
  "335 raw maize",
  "399 barley",
  "400 green beans",
]

const rx = /^([12][0-9]{2}|300)\s./

const filtered = strings.filter(str => rx.test(str))

console.log(filtered)
.as-console-wrapper { max-height: 100% !important; }
Phil
  • 157,677
  • 23
  • 242
  • 245
5

That is because in your pattern, it also matches 3xx where x can be any digit and not just 0. If you change your pattern to match 1xx, 2xx and 300 then it will return the result as you intended, i.e.:

/^([12][0-9][0-9]|300)\s.*/g

See example below:

const str = `
99 Apple
100 banana
101 pears
200 wheat
220 rice
300 corn
335 raw maize
399 barley
400 green beans
`;

const matches = str.split('\n').filter(s => s.match(/^([12][0-9][0-9]|300)\s.*/));
console.log(matches);

However, using regex to match numerical values might not be as intuitive than simply extracting any numbers from a string, converting them to a number and then simply using mathematical operations. We can use the unary + operator to convert the matched number-like string as such:

const str = `
99 Apple
100 banana
101 pears
200 wheat
220 rice
300 corn
335 raw maize
399 barley
400 green beans
`;

const entries = str.split('\n').filter(s => {
  const match = s.match(/\d+\s/);
  return match !== null && +match[0] >= 100 & +match[0] <= 300;
});
console.log(entries);
Terry
  • 63,248
  • 15
  • 96
  • 118
  • @Phil That depends on OP's string input. Based on the examples he has provided, the code generates the output he expects. – Terry Jun 09 '21 at 06:13
  • I was just referencing their requirement... _"I need to match the strings that **start with**..."_ – Phil Jun 09 '21 at 06:14
  • for the second option. Much better IMO – Phil Jun 09 '21 at 06:18
  • I'm curious about the `g` flag. Any reason to use it when you're only interested in one match at the start of the string? – Phil Jun 09 '21 at 06:31
  • @Terry, the `g` flag in second example is unnecessary, in fact you don't have to capture anything, simple `/\d+\s/` will work. Also don't need match `null` specifically – vanowm Jun 09 '21 at 06:46
  • There's no need for the `+`. [Why does string to number comparison work in Javascript](https://stackoverflow.com/a/28994875/1115360): "In the case of <, >, <=, and >= [...] it coerces the operands to numbers and does a numeric comparison." – Andrew Morton Jun 09 '21 at 07:20