66

A quick search for currency regex brings up a lot of results.

The problem I have in choosing one is that regex is difficult to verify without testing all the edge cases. Does anyone have a regex for U.S. currency that has been thoroughly tested?

My only requirement is that the matched string is U.S. currency and parses to System.Decimal:

[ws][sign][digits,]digits[.fractional-digits][ws] 

Elements in square brackets ([ and ]) are optional. 
The following table describes each element. 

ELEMENT             DESCRIPTION
ws                  Optional white space.
sign                An optional sign.
digits              A sequence of digits ranging from 0 to 9.
,                   A culture-specific thousands separator symbol.
.                   A culture-specific decimal point symbol.
fractional-digits   A sequence of digits ranging from 0 to 9. 
Robert Claypool
  • 4,083
  • 9
  • 47
  • 59

12 Answers12

103

here's some stuff from the makers of Regex Buddy. These came from the library so i'm confident they have been thoroughly tested.

Number: Currency amount (cents mandatory) Optional thousands separators; mandatory two-digit fraction

Match; JGsoft:
^[+-]?[0-9]{1,3}(?:,?[0-9]{3})*\.[0-9]{2}$

Number: Currency amount (cents optional) Optional thousands separators; optional two-digit fraction

Match; JGsoft:
^[+-]?[0-9]{1,3}(?:,?[0-9]{3})*(?:\.[0-9]{2})?$

Number: Currency amount US & EU (cents optional) Can use US-style 123,456.78 notation and European-style 123.456,78 notation. Optional thousands separators; optional two-digit fraction

Match; JGsoft:
^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{2})?|(?:,[0-9]{3})*(?:\.[0-9]{2})?|(?:\.[0-9]{3})*(?:,[0-9]{2})?)$
Keng
  • 48,571
  • 31
  • 77
  • 109
  • Do you have a link to the Regex Buddy library? Is it posted online? – Robert Claypool Dec 09 '08 at 22:04
  • i don't have a link to it; it's part of the software. – Keng Dec 10 '08 at 03:54
  • 2
    Very old now but this regex does not handle the optional commas very well. The number `11111111,111,111111.11` is obviously malformed, but this regex will match it. – OGHaza Dec 15 '13 at 21:10
  • @OGHaza note comment on thousands separators. also, note the question did not ask nor require thousands separators. the answer was for the question asked not for a different question. – Keng Dec 16 '13 at 17:10
  • 2
    @Keng, I agree it meets OPs needs, was only making note since this is the answer to a question called `What is “The Best” U.S. Currency RegEx` – OGHaza Dec 16 '13 at 17:12
  • @OGHaza but you down-voted it for answering the question asked, that's what confuses me. it answers the OP's question, notes something the OP may not have foreseen, and you still down-voted it? – Keng Dec 16 '13 at 19:00
  • 7
    I think we can fix the optional comma issue by replacing `(?:,?[0-9]{3})*` with something like `(?:(,[0-9]{3})*|([0-9]{3})*)`. Commas everywhere or no commas. – regularmike Feb 24 '15 at 16:37
  • On the 3rd regex, you don't need to escape the periods in Xcode, so you get a warning. Fix: `^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{2})?|(?:,[0-9]{3})*(?:.[0-9]{2})?|(?:.[0-9]{3})*(?:,[0-9]{2})?)$` – Big Money Apr 22 '16 at 20:42
  • @Keng No they down voted because this answer is wrong. It actually does not fulfill the requirements OP wanted because the matched string is not U.S. Currency. This answer is misleading to future visitors like myself that actually wanted a regexp that only matched U.S. Currency, unless they noticed regularmike's comment. Along with that this answer also accepts leading zeros such as: `01234`. – Spencer Wieczorek Jul 26 '17 at 17:21
  • @SpencerWieczorek....4 years?....really.....you're jumping into a discussion even the people who were in it don't care about, 4 years later?...really? – Keng Aug 10 '17 at 18:36
  • [0-9]{1,3} allows numbers like 0,123. I'd recommend [1-9][0-9]{0,2} – ThePatelGuy Oct 19 '17 at 22:56
  • 1
    This answer would be improved with example numbers above the regex, rather than (or as well as) word descriptions. – Andrew Mar 23 '19 at 23:54
  • 6
    @Keng It is 2020 and I still care - regex expressions don't expire like milk. – gsn1074 Apr 11 '20 at 10:05
20

I found this regular expression on line at www.RegExLib.com by Kirk Fuller, Gregg Durishan

I've been using it successfully for the past couple of years.

"^\$?\-?([1-9]{1}[0-9]{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\-?\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\(\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))\)$"
Developer
  • 8,043
  • 35
  • 115
  • 224
9

Not thoroughly tested at all (I just wrote it!), but seems to behave correctly:

^-?(?:0|[1-9]\d{0,2}(?:,?\d{3})*)(?:\.\d+)?$

Test set:

0
1
33
555
4,656
4656
99,785
125,944
7,994,169
7994169
0.00
1.0
33.78795
555.12
4,656.489
99,785.01
125,944.100
-7,994,169
-7994169.23 // Borderline...

Wrong:
000
01
3,3
5.
555,
,656
99,78,5
1,25,944
--7,994,169
0.0,0
.10
33.787,95
4.656.489
99.785,01
1-125,944.1
-7,994E169

Note: Your System.Decimal is locale dependent, hard to make in regex, except perhaps when building it. I assumed digits being grouped by three, even if in some cultures (locales) there are different rules.
It is trivial to add whitespace around it.

PhiLho
  • 38,673
  • 6
  • 89
  • 128
  • @RonRoyston The original question required digits to be present before the decimal symbol... (see the `.10` case in the wrong testset). And `0.75` does pass, when I go to https://regex101.com/, paste my expression and add your two cases. – PhiLho Oct 05 '18 at 13:46
3

The answer of Keng is perfect, I just want add that for working with 1 or 2 decimals (for third version) :

"^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{1})?|(?:,[0-9]{3})*(?:\.[0-9]{1,2})?|(?:\.[0-9]{3})*(?:,[0-9]{1,2})?)$

NET FIDDLE: https://dotnetfiddle.net/1mUpX2

Leandro
  • 6,537
  • 12
  • 59
  • 95
1

In case you want to account for human error you could make the the regex more forgiving when matching currency. I used Keng's 2nd nice regex and made it a bit more robust to account for typo's.

\$\ ?[+-]?[0-9]{1,3}(?:,?[0-9])*(?:\.[0-9]{1,2})?

This will match any of these proper or mangled currency figures but not pick up the extra junk on the end after the space:

$46,48382
$4,648,382
$ 4,648,382
$4,648,382.20
$4,648,382.2
$4,6483,82.20
$46,48382 70.25PD
$ 46,48382 70.25PD
jim
  • 33
  • 9
1

This question is a few years old, so I wanted to give an updated answer.

I have used jQuery InputMask and it works very well for input/format masking (such as phone numbers, etc) but it does NOT really work well for currency from my experience.

For currency, I strongly recommend autoNumeric jQuery plugin. It's well-maintained and they've basically "thought of everything" I could want for currency.

I actually use a combination of both of these plugins for formatting phone numbers, number formats (ISBN, etc), as well as currencies (US currency mostly).

Keep in mind that jquery.inputmask is mostly about controlling a value's format, whereas autoNumeric is about specifically controlling the format of currency.

Dan L
  • 3,896
  • 3
  • 30
  • 63
  • Indeed, trying to use a regex only will only lead you to pain and despair. Take a look at the number of AutoNumeric lines of code (as of today) : `~/dev/autoNumeric » cat src/*|wc -l ` -> **10851**. This is just the most complete library today for formatting currencies, and it's *thoroughly tested* indeed ;) *(Disclaimer; I'm one of it's maintainer)* – Alex Jul 20 '17 at 06:12
  • Can you give an example with using this library to extract a currency value from a string? – Ari Mar 28 '19 at 14:10
  • 1
    @Ari: these libraries are more about controlling the format of data when a user enters them into input fields; I don't use them for extracting currency from strings. To extract currency from a string you could use regex to remove anything that isn't 0-9 and a decimal, and then convert that to a float, and then I recommend storing monetary values as cents in the DB. Untested pseudocode: `"$123,456.78".gsub(/^[0-9]\./, "").to_f => 123456.78` (note this allows multiple decimal places, but proof of concent). – Dan L Mar 28 '19 at 20:05
1

regex_expression

/^[-]?[$]\d{1,3}(?:,?\d{3})*\.\d{2}$/ is what I came up with - I see similar answers, but I just used \d instead of [0-9]

abumalick
  • 1,512
  • 15
  • 22
0

I've had success with this (taking bits and pieces from some of the regexs above). Only handles up to thousands, but should be not too hard to extend that

case class CurrencyValue(dollars:Int,cents:Int)
def cents = """[\.\,]""".r ~> """\d{0,2}""".r ^^ {
  _.toInt
}
def dollarAmount: Parser[Int] = """[1-9]{1}[0-9]{0,2}""".r ~ opt( """[\.\,]""".r ~> """\d{3}""".r) ^^ {
  case x ~ Some(y) => x.toInt * 1000 + y.toInt
  case x ~ None => x.toInt
}
def usCurrencyParser = """(\$\s*)?""".r ~> dollarAmount ~ opt(cents) <~ opt( """(?i)dollars?""".r) ^^ {
  case d ~ Some(change) => CurrencyValue(d, change)
  case d ~ None => CurrencyValue(d, 0)
}
JoshMahowald
  • 433
  • 5
  • 8
0

This is what I use:

Without leading + or -

^\$\d{1,3}\.[0-9]{2}$|^\$(\d{1,3},)+\d{3}\.[0-9]{2}$

With optional leading + or -

^[+-]?\$\d{1,3}\.[0-9]{2}$|^[+-]?\$(\d{1,3},)+\d{3}\.[0-9]{2}$

net fiddle: https://jsfiddle.net/compsult/9of63cwk/12/

MIkee
  • 700
  • 7
  • 11
0

Using Leandro's answer I added ^(?:[$]|) to the beginning to allow for a preceding dollar sign

^(?:[$]|)[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{1})?|(?:,[0-9]{3})*(?:\.[0-9]{1,2})?|(?:\.[0-9]{3})*(?:,[0-9]{1,2})?)$

This matched

136,402.99
25.27
0.33
$584.56
1
00.2
3,254,546.00
$3,254,546.00
00.01
-0.25
+0.85
+100,052.00

Did Not Match

11124.52
234223425.345
234.
.5234
a
a.23
32.a
a.a
z548,452.22
u66.36
0

I'm using the following regular expression for currency validation:

^-?0*(?:\d+(?!,)(?:\.\d{1,2})?|(?:\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?))$

You can also allow optional leading dollar sign:

^\$?-?0*(?:\d+(?!,)(?:\.\d{1,2})?|(?:\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?))$

You can easily add testing for parentheses instead of sign by adding

\( and \)
eitanpo
  • 324
  • 1
  • 10
-1

I was looking at this too and have come to the conclusion that it is best to build the regex based on the current culture. We can use the

CurrencyPositivePattern 
CurrencyGroupSeparator
CurrencyDecimalSeparator

properties of NumberFormatInfo to get the required format.

Edit: something like this

NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
      // Assign needed property values to variables.
      string currencySymbol = nfi.CurrencySymbol;
      bool symbolPrecedesIfPositive = nfi.CurrencyPositivePattern % 2 == 0;
      string groupSeparator = nfi.CurrencyGroupSeparator;
      string decimalSeparator = nfi.CurrencyDecimalSeparator;

      // Form regular expression pattern.
      string pattern = Regex.Escape( symbolPrecedesIfPositive ? currencySymbol : "") + 
                       @"\s*[-+]?" + "([0-9]{0,3}(" + groupSeparator + "[0-9]{3})*(" + 
                       Regex.Escape(decimalSeparator) + "[0-9]+)?)" + 
                       (! symbolPrecedesIfPositive ? currencySymbol : ""); 

refer - http://msdn.microsoft.com/en-us/library/hs600312.aspx

NoviceProgrammer
  • 3,189
  • 1
  • 19
  • 31