6

Possible Duplicate:
What's a C# regular expression that'll validate currency, float or integer?

How can I validate currency amount using regular expressions in JavaScript?

Decimals separator: ,

Tens, hundreds, etc. separator: .

Pattern: ###.###.###,##

Examples of valid amounts:

1
1234
123456

1.234
123.456
1.234.567

1,23
12345,67
1234567,89

1.234,56
123.456,78
1.234.567,89

EDIT

I forgot to mention that the following pattern is also valid: ###,###,###.##

Community
  • 1
  • 1
Diogo Cardoso
  • 21,637
  • 26
  • 100
  • 138

3 Answers3

17

Based solely on the criteria you gave, this is what I came up with.

/(?:^\d{1,3}(?:\.?\d{3})*(?:,\d{2})?$)|(?:^\d{1,3}(?:,?\d{3})*(?:\.\d{2})?$)/

Demo

It is ugly, and it will only get worse as you find more cases that need to be matched. You'd be well served to find and use some validation library rather than try to do this all yourself, especially not in a single regular expression.

Updated to reflect added requirements.


Updated again in regard to comment below.

It would match 123.123,123 (three trailing digits instead of two) because it would accept either comma or period as both the thousands and decimal separators. To fix that, I've now essentially doubled up the expression; either it matches the whole thing with commas for separators and a period as the radix point, or it matches the whole thing with periods for separators and a comma as the radix point.

See what I mean about it getting messier? (^_^)


Here's the verbose explanation:

(?:^           # beginning of string
  \d{1,3}      # one, two, or three digits
  (?:
    \.?        # optional separating period
    \d{3}      # followed by exactly three digits
  )*           # repeat this subpattern (.###) any number of times (including none at all)
  (?:,\d{2})?  # optionally followed by a decimal comma and exactly two digits
$)             # End of string.
|              # ...or...
(?:^           # beginning of string
  \d{1,3}      # one, two, or three digits
  (?:
    ,?         # optional separating comma
    \d{3}      # followed by exactly three digits
  )*           # repeat this subpattern (,###) any number of times (including none at all)
  (?:\.\d{2})? # optionally followed by a decimal perioda and exactly two digits
$)             # End of string.

One thing that makes it look more complicated is all the ?: in there. Normally a regular expression captures (returns matches for) all of the subpatterns too. All ?: does is say to not bother to capture the subpattern. So technically, the full thing would still match your entire string if you took all of the ?: out, which looks a bit clearer:

/(^\d{1,3}(\.?\d{3})*(,\d{2})?$)|(^\d{1,3}(,?\d{3})*(\.\d{2})?$)/

Also, regular-expressions.info is a great resource.

mousetail
  • 7,009
  • 4
  • 25
  • 45
Wiseguy
  • 20,522
  • 8
  • 65
  • 81
  • Before I accept your answer could you update the regular expression so it doesn't accept more than two decimals? Example: 123.456,789 – Diogo Cardoso May 31 '11 at 16:54
  • @Diogo Good call, see my update. – Wiseguy May 31 '11 at 17:20
  • could you please update the following verbose regex: http://pastebin.com/2heBURP7 – Diogo Cardoso Jun 03 '11 at 20:46
  • @Diogo Like this? http://pastebin.com/at8hhuUt One thing that makes it look more complicated is all the `?:` in there. Normally a regex captures (returns matches for) all of the subpatterns too. All `?:` does is say to not bother to capture the subpattern. So technically, it would still match your entire string if you took all of them out, which looks a bit clearer: `/(^\d{1,3}(\.?\d{3})*(,\d{2})?$)|(^\d{1,3}(,?\d{3})*(\.\d{2})?$)/` – Wiseguy Jun 03 '11 at 22:06
8

This works for all your examples:

/^(?:\d+(?:,\d{3})*(?:\.\d{2})?|\d+(?:\.\d{3})*(?:,\d{2})?)$/

As a verbose regex (not supported in JavaScript, though):

^              # Start of string
(?:            # Match either...
 \d+           # one or more digits
 (?:,\d{3})*   # optionally followed by comma-separated threes of digits
 (?:\.\d{2})?  # optionally followed by a decimal point and exactly two digits
|              # ...or...
 \d+           # one or more digits
 (?:\.\d{3})*  # optionally followed by point-separated threes of digits
 (?:,\d{2})?   # optionally followed by a decimal comma and exactly two digits
)              # End of alternation
$              # End of string.
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • 4
    +1 for explaining each section of the regular expression, otherwise they have the ability to burn your eyes. – codingbadger May 31 '11 at 16:59
  • +1 Agreed with Barry. Thanks for adding this. I was going to do so after the requirements and my answer were finalized, but you beat me to it. – Wiseguy Jun 03 '11 at 22:11
0

This handles everything above except for the (just added?) 123.45 case:

function foo (s) { return s.match(/^\d{1,3}(?:\.?\d{3})*(?:,\d\d)?$/) }

Do you need to handle multiple separator formats?

Tamzin Blake
  • 2,594
  • 20
  • 36