Regex Extraction - Mixed Decimal seperator

Viewed 64

I am currently trying to write a regex in js that would extract the decimal numbers from a mixed string.

Example strings are following

mixed string123,456,00indeed
mixed string123,456.00indeed
mixed string123,4indeed
mixed string123,40indeed
mixed string 1,0
mixed string 1,00indeed
mixed string 1,00.00indeed

My desired output is following

123,456,00
123,456.00
123,4
123,40
1,0
1,00
1,00.00

If I run the following regex

(\d+\,)+(.)+(\d+)

it doesnot return any match when the decimal point is followed by a single digit.Eg. following cases

mixed string123,4indeed
mixed string 1,0

I am not sure how to tune the regex that works for all such cases. If someone can please help me would be very helpful. The full js here

var str='mixed string123,4indeed';
str.match(/(\d+\,)+(.)+(\d+)/gm);

Regex101screenshot

Also I am getting this in regex101 which I am not sure how to decipher

A repeated capturing group will only capture the last iteration. Put a capturing group around the repeated group to capture all iterations or use a non-capturing group instead if you're not interested in the data
2 Answers

The regex ... /\D+([\d,.]+)/g ... of the below provided example code reads as follows ...

  • / ... /g ... globally match ...
  • ... \D+ ... any character (sequence) which is not a digit ...
  • ... ([\d,.]+) ... followed by a character (sequence) of just either digit or comma or dot ...
  • ... which has to be captured ... ( ... ).

Passing this regex to matchAll does return an iterator object, which can be casted into an array. In case of (a) successful match(es) this array is not empty and can be mapped into e.g. the desired end result ...

const sampleText = `mixed string123,456,00indeed
  mixed string123,456.00indeed
  mixed string123,4indeed
  mixed string123,40indeed
  mixed string 1,0
  mixed string 1,00indeed
  mixed string 1,00.00indeed`;

console.log([

  // see [https://regex101.com/r/QduIQl/1]
  ...sampleText.matchAll(/\D+([\d,.]+)/g)

  ].map(([match, capture]) => capture)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

The even more specific regex ... \d+(?:[,.]\d+)* ... straightforwardly matches a precise pattern. Thus the example code's implementation can be simplified to something clean like ...

sampleText.match(/\d+(?:[,.]\d+)*/g)

The regex itself reads as follows ...

  • / ... /g ... globally match ...
  • \d+ ... a digit (sequence) followed by ...
  • (?: ... )* ... an optional and possibly repeating (*) uncaptured (?:) group ((...)) of following pattern ...
  • [,.]\d+ ... either a single comma or a single dot followed by a digit (sequence).

const sampleText = `mixed string123,456,00indeed
  mixed string123,456.00indeed
  mixed string123,4indeed
  mixed string123,40indeed
  mixed string 1,0
  mixed string 34.
  mixed string 21
  mixed string 1,00indeed
  mixed string 1,00.00indeed`;

console.log(
  // see [https://regex101.com/r/QduIQl/3]
  sampleText.match(/\d+(?:[,.]\d+)*/g)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

You can use

/\d+(?:,\d+)*(?:\.\d+)?/g

See the regex demo.

Details:

  • \d+ - one or more digits
  • (?:,\d+)* - zero or more occurrences of a comma and one or more digits
  • (?:\.\d+)? - an optional occurrence of a dot and one or more digits.

See the JavaScript demo:

var texts = ['mixed string123,456,00indeed','mixed string123,456.00indeed','mixed string123,4indeed','mixed string123,40indeed','mixed string 1,0','mixed string 1,00indeed','mixed string 1,00.00indeed'];
var rx = /\d+(?:,\d+)*(?:\.\d+)?/g
for (var i=0; i<texts.length;i++) {
  console.log(texts[i], '->', (texts[i].match(rx) || ["No match!"])[0]);
}

Related