3

Can anybody provide an algorithm that checks whether an input string is a decimal number in correct shape and form?

Rules of correct shape and form:

  1. At most two decimal places.
  2. For all practical purposes, the largest number is 99,999,999.99
  3. The integral part can use a space, or a comma, or a dot for a group separator.
  4. The decimal part can use a comma, or a dot for a separator.

Examples of correct shape and form:

1,234,567.89   // English style
1.234.567,89   // French style
1 234 567,89   // German style
1234567.89     // English mathematical style
1234567,89     // European mathematical style
12.00
12.0
12

Please, resist your temptation to propose Decimal.Parse or Decimal.TryParse. Either method merrily accepts strings such as “1,2,3,4”, which is not what I want.

user669226
  • 661
  • 1
  • 7
  • 16

3 Answers3

5

I answered a very similar question on Friday, and the regex to do this is going to be more complicated than you think. I strongly suggest setting up a separate regex for each style - not because it can't be done in one line, but because a one-liner for this is going to be big and pretty tough to maintain.

Here are the patterns I'd use:

English: ^[-+]?\d{1,3}(,\d{3})*(\.\d+)?$
French: ^[-+]?\d{1,3}(\.\d{3})*(,\d+)?$
German: ^[-+]?\d{1,3}(\s\d{3})*(,\d+)?$
English mathematical: ^[-+]?\d+(\.\d+)?$
European mathematical: ^[-+]?\d+(,\d+)?$

These can be combined into something like:

^[-+]?(\d{1,3}((,\d{3})*(\.\d+)?|([.\s]\d{3})*(,\d+)?)|\d+([,\.]\d+)?)$

Hopefully that one-liner is appropriately terrifying to you. This is a very common, important task, but it's also one that's more complicated than it appears.

Tested at Rubular with your example inputs: http://rubular.com/r/Dipvyrf6C8 (note that I made the groups non-capturing for clarity of the results).

Edit: Added [-+]? clause to allow for negative numbers.

Community
  • 1
  • 1
Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
  • @justin morgan --- The short patterns fail to recognize strings such as "0.00", "0.0", "0,00", "0,0". That means a single digit to the left of the decimal point or comma. This works "10.00", 10,00". – user669226 May 09 '11 at 09:13
  • @justin morgan --- Strings such as "0.00", "0.0", "0,00", "0,0". That means a zero(s) to the left of the decimal point or comma. – user669226 May 09 '11 at 11:33
  • @justin morgan --- This is a very lame commenting system. Can't edit. Anyways, another problem with the long pattern: Strings such as"0000,00" or "0000.00" – user669226 May 09 '11 at 11:46
  • @user669226 - [The long form currently accepts those strings as numbers,](http://rubular.com/r/2Vc8Wcd8jq) but they can be disallowed if you want; let me know and I can edit. Personally, I would leave them in, because 0000.00 is very conceivable as an input, and it's in the correct format. – Justin Morgan - On strike May 09 '11 at 14:00
  • @user669226 - [As I mentioned in the other answer I linked to,](http://stackoverflow.com/questions/5917082/regular-expression-to-match-numbers-with-or-without-commas-and-decimals-in-text/5917250#5917250) the previous pattern intentionally disallowed leading zeroes. I went ahead and edited because I prefer the simpler form, and I feel like it's more correct anyway. The other form was mostly just to show how to disallow leading zeroes **if you want to do that.** Be aware that numbers like 00,123,456.789 will now be allowed, but I would consider that the correct behavior. – Justin Morgan - On strike May 09 '11 at 14:03
0

use this Simple regular expression for a decimal with a precision of 2

Community
  • 1
  • 1
Chen Kinnrot
  • 20,609
  • 17
  • 79
  • 141
0

If it's guaranteed that there will be a decimal part, then one way to do it would be:

var s = "1 334 567,80";
var decimalPart = s.Split(',', '.').Last();
var integerPart = s.Substring(0, s.Length - decimalPart.Length - 1);
integerPart = integerPart.Replace(",", string.Empty).Replace(".", string.Empty)
                         .Replace(" ", string.Empty);

var decimalValue = decimal.Parse(integerPart + "." + decimalPart,
                                 CultureInfo.InvariantCulture);

If the decimal part is optional, I 'm not sure if you can unambiguously parse this format.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • How does your algorithm handle a string such as "1,2,3,80"? Does you algorithm consider the string a valid representation of a decimal number? – user669226 May 08 '11 at 13:44