Multiple things are wrong in your expression :
^\{USD}?(\d*(\d\.?|\.\d{1,2}))$
\{USD}?
in regex language this would mean: expect the {
literal character followed by USD
followed by the character }
if any. If you want to have an optional group USD
you have to use parenthesis without \
: (USD)?
. You can use a non-capturing group for this : (?:USD)?
.
This would give : ^(USD)?(\d*(\d\.?|\.\d{1,2}))$
(\d\.?|\.\d{1,2})
, the whole group should be repeated in order to match the entire string : (\d\.?|\.\d{1,2})*
This would give : ^(USD)?(\d*(\d\.?|\.\d{1,2})*)$
\d\.?
: if this is supposed to match the part with a thousand separator it should be a comma not a point regarding your example: \d*,?
This would give : ^(USD)?(\d*(\d,?|\.\d{1,2})*)$
(\d*(\d
: this won't work, the second \d
will never match because all digit will be consumed by the first \d*
, you could use the non-greedy operator ?
like this: (\d*?(\d
but it's not pretty.
This would give : ^(USD)?(\d*?(\d,?|\.\d{1,2})*)$
which may work for you, but looks less than optimal.
An alternative would be to build your regular expression without an "or" clause using the following parts :
- The prefix : "USD ", optional and with optional space :
(USD ?)?
- The integral part of the amount before the thousand separators:
\d+
- The integral part of the amount with a thousand separator, optional and repeatable:
(,\d+)*
- The decimal part, optional :
(\.\d+)?
Wich would give something like that: (USD ?)?(\d+)(,\d+)*(\.\d+)?
You can test it on regex101.com
You can further restrict the number of digits in each parts to avoid false-positive :
(USD ?)?(\d{1,3})(,\d{3})*(\.\d{1,2})?
A final version would be optimized with non-capturing groups unless necessary:
(?:USD ?)?(?:\d{1,3})(?:,\d{3})*(?:\.\d{1,2})?
Edit: the test case you provided uses incoherent use of decimal separators (sometime ".", sometimes ","). If you really want to match that, you can use a character class like this :
(?:USD ?)?(?:\d{1,3})(?:,\d{3})*(?:[.,]\d{1,2})?
Which matches every number in your example :
