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.

6
  • 1
    Sounds like you want to write a regular expression Commented May 8, 2011 at 12:49
  • 1
    Are those the only examples of "correct shape and form"? Commented May 8, 2011 at 12:49
  • Please can you define the rules. Giving a handful of examples does not a specification make. Commented May 8, 2011 at 13:01
  • 3
    Also, with 9 questions asked, you should have accepted at least one by now. Commented May 8, 2011 at 13:01
  • 1,2,3,4 seems valid according to your requirements. I am surprised that Parse methods do not honour the number format group size though. Commented May 8, 2011 at 13:35

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

5 Comments

@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".
@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.
@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 - The long form currently accepts those strings as numbers, 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.
@user669226 - As I mentioned in the other answer I linked to, 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.
0

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

Comments

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.

1 Comment

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?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.