Frederik
Frederik

Reputation: 13

Regex matching multiple inputs

I am trying to do a smart input field for UK style weight input, e.g. "6 stone and 3 lb" or "6 st 11 pound", capturing the 2 numbers in groups.

For now I got: ([0-9]{1,2}).*?([0-9]{1,2}).*

Problem is it matches "12 stone" in 2 groups, 1 and 2 instead of just 12. Is it possible to make a regex which captures correctly in both cases?

Upvotes: 1

Views: 189

Answers (7)

N3dst4
N3dst4

Reputation: 6435

Seeing as everyone is having a go, here's mine:

(\d+)(?:\D+(\d+)?)

It's definitely the concisest so far. This will match one or two groups of digits anywhere:

"12": ("12", null)
"12st": ("12", null)
"12 st": ("12", null)
"12st 34 lb": ("12", "34")
"cabbage 12st 34 lb": ("12", "34")
"12 potato 34 moo": ("12", "34")

The next step would be making it catch the name of the units that were used.

Edit: as pointed out above, we don's know what language you're using, and not all regex functionality is available in all implementations. However as far as I know, \d for digits and \D for non-digits is fairly universal.

Upvotes: 0

ian
ian

Reputation: 12251

It's a bit vague at the moment, this works:

/([0-9]{1,2})(?:[^0-9]+([0-9]{1,2}).*)?/

for this data:

6 stone and 3 lb
6 st 11 pound
12 stone
12 st and 11lbs

Upvotes: 0

Fischermaen
Fischermaen

Reputation: 12458

Here is my suggestion for a regex to match both variants you showed:

(?<stone>\d+\s(?:stone|st))(?:\s(and)?\s?)(?<pound>\d+\s(?:pound|lb))

Upvotes: 0

heneryville
heneryville

Reputation: 2929

This works, then look at capture groups 1 and 3: ([0-9]{1,2})[^0-9]+(([0-9]{1,2})?.+)?

The idea is to make a number and text manditory, but make a second number and text optional.

Upvotes: 0

SERPRO
SERPRO

Reputation: 10067

Because . matches everythig including numbers.. try this:

/(\d{1,2})\D+(\d{1,2})?/

Upvotes: 2

FailedDev
FailedDev

Reputation: 26930

Something like this?

\b(\d+)\b.*?\b(\d+)\b

Groups 1 and 2 will have your numbers in either case.

Explanation :

"
\b       # Assert position at a word boundary
(        # Match the regular expression below and capture its match into backreference number 1
   \d       # Match a single digit 0..9
      +        # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\b       # Assert position at a word boundary
.        # Match any single character that is not a line break character
   *?       # Between zero and unlimited times, as few times as possible, expanding as needed (lazy)
\b       # Assert position at a word boundary
(        # Match the regular expression below and capture its match into backreference number 2
   \d       # Match a single digit 0..9
      +        # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\b       # Assert position at a word boundary
"

Upvotes: 1

Geert
Geert

Reputation: 1824

You need to make the first part possessive so it never gets backtracked into.

([0-9]{1,2}+).*?([0-9]{1,2})

Upvotes: 2

Related Questions