Tiago Fernandez
Tiago Fernandez

Reputation: 1473

Javascript: replace everything but numbers and allow only one dot

This works for integers, e.g.:

'123x'.replace(/\D/g, '')
'123'

Which regular expression would achieve the same, but allowing only one dot? Examples:

Upvotes: 4

Views: 4845

Answers (6)

esenkaya
esenkaya

Reputation: 408

This would be a good and simple solution if you want to trim everything but numbers along with only the first occurrence of the dots.

"ab12..34..c".replace(".", "~").replace(/[^0-9~]/g, "").replace("~", ".")

OUTPUT: 12.34

1s replace: Assigning the first dot (.) to tilde (~). 2nd replace: Keeping only numbers and the tilde (there is only one). 3rd replace: Replacing tilde with dot.

Upvotes: 0

trincot
trincot

Reputation: 350272

With two replaces:

console.log("a12b3.1&23.0a2x".replace(/[^.\d]/g, '')
                             .replace(/^(\d*\.?)|(\d*)\.?/g, "$1$2"));

The first action will remove all characters other than digits and points

The second replacement matches sequences of digits possibly followed by a point, but it does so in two different ways. When such sequence occurs at the start of the string, the optional point is put inside the first capture group, while for all other matches, the point is outside the (second) capture group.

There are two capture groups, but for any given match, only one of them will actually have content. So the captured content can be reproduced in either case with $1$2. This will include the first point, but exclude any other.

Upvotes: 18

Christoph Herold
Christoph Herold

Reputation: 1809

UPDATE

Why not simply do it old school:

    function formatNumber(s) {
        var hadDot = false, result = '';
        for (var i = 0; i < s.length; i++) {
            var c = s[i];
            if (c >= '0' && c <= '9')
              result += c;
            else if (!hadDot && c == '.') {
              hadDot = true;
              result += c;
            }
        }
        return result;
    }
    var inputs = ['10.01.x23.5asd6', '10.', '10', '.12vx12.1f53', '10.10.'];
    for (var i = 0; i < inputs.length; i++) {
      console.log(formatNumber(inputs[i]));
    }

Requires just one iteration of the string, so you probably won't get any better running time.

OLD ANSWER, WON'T WORK

This should also work (but it doesn't, thanks to trincot for pointing it out):

function formatNumber(s) {
    return s.replace(/[^\d\.]/g, '').replace(/\.(([^\.]*)\.)*/g, '.$2');
}
var inputs = ['10.01.x23.5asd6', '10.', '10', '.12vx12.1f53', '10.10.'];
for (var i = 0; i < inputs.length; i++) {
  console.log(formatNumber(inputs[i]));
}

First, replace all non-digits and dots. Then, capture everything after the first dot, and replace it with anything that is not a dot. But, it needs a two step regex.

Upvotes: 1

Loc Mai
Loc Mai

Reputation: 217

let arr = ['1', '1x', '10.', '10.0', '10.01', '10.01x', '10.01.', '10.01.23', 'a1b2c3d.e4f5g6h'];

arr.forEach(val => {
	val = val.replace(/[^\d.]/g, '').match(/([0-9]+(\.[0-9]*)?)/);
	if (val) console.log(val[0]);
})

replace(/[^\d.]/g, '') to replace any non-digit character and non . character.

[0-9]+ digits from 0 to 9 will be matched, and + for match one or more time

. followed by a dot.

[0-9]*? matched from 0 to 9 (but match ZERO or more time)

Upvotes: 0

Pranav C Balan
Pranav C Balan

Reputation: 115222

You can do something like this, need two replace methods:

  1. For removing everything except digit and dot. For that use negated character class `[^\d.].
  2. For removing duplicate dots use replace with callback where we need to replace content after the first dot so use \.([.\d]+)$ to match entire string after first do(including the dot) and within callback remove all the remaining dots from the captured value(string after the first dot).

'123x'.replace(/[^\d.]/g, '').replace(/\.([.\d]+)$/,function(m,m1){
   return '.' + m1.replace(/\./g, '')
})

DEMO :

var arr = ['1', '1x', '10.', '10.0', '10.01', '10.01x', '10.01.', '10.01.23', 'a1b2c3d.e4f5g6h'];

function format(str) {
  return str.replace(/[^\d.]/g, '').replace(/\.([.\d]+)$/, function(m, m1) {
    return '.' + m1.replace(/\./g, '')
  });
}

arr.forEach((v) => console.log(`${v} => ${format(v)}`))

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386604

You could use parseFloat and convert back to a string.

console.log(parseFloat('10.01.x').toString());

An approach with a regular expression.

function convert(s) {
    return s.match(/^\d+\.?\d*/)[0];
}

console.log(['1', '1x', '10.', '10.0', '10.01', '10.01x', '10.01.'].map(convert));

Upvotes: 3

Related Questions