Regex for Prices

Price tags come in various shapes and sizes around the Internet. Some have 2 decimal digits (e.g. 0.99), others include a currency symbol (such as $8.79), and some have neither (e.g. 100). Is it possible to write a regular expression to match these?

A regular expression to match prices should preferably look for at least one digit, followed by an optional decimal separator (either period or comma), followed by at most two decimal digits. More advanced expressions can also match thousand’s separators as well as currency symbols.

There are many forms that a price tag can take, and it is difficult to create an expression that matches all valid prices, without also including unwanted matches.

A generally acceptable expression might look like the following:

/\d+(?:[.,]\d{0,2})?/Edit with Regexity

Let’s break this down and see how it all works.

General Format of a Price Tag

Prices generally have at least one digit before a decimal separator, followed by a decimal separator (either a period or a comma), and then followed by at most two digits. For example 1.99Edit with Regexity has a period decimal separator and 50,69Edit with Regexity has a comma. A price like 100Edit with Regexity has no decimal value but is still considered a valid price

Some are preceded by a currency symbol such as $1.99Edit with Regexity or €5.59Edit with Regexity, with an optional space between the symbol and value, i.e. $ 1.99Edit with Regexity.

Some sites specify currencies using a 3-character currency code behind the price, such as 100 USDEdit with Regexity or 4.55 AUDEdit with Regexity, with the space between the value and the currency code also being optional.

Larger prices might generally contain a thousand’s separator, typically in the form of a comma or a space, for example 1,000.00Edit with Regexity or 5 000 000Edit with Regexity.

Matching Numeric Values with Optional Decimal Digits

To kick off our expression, we’ll start with the digit character set \dEdit with Regexity that matches any digit from 0 to 9:

/\d/Edit with Regexity

This will only match a single digit, so to include more digits we can include a one-or-more quantifier +Edit with Regexity behind the digit character set.

/\d+/Edit with Regexity

Using the zero-or-more quantifier here might be useful if you want to include prices such as .99Edit with Regexity with no leading digit.

/\d*/Edit with Regexity

Next, we can include a decimal separator, which usually comes in the form of a period .Edit with Regexity or a comma ,Edit with Regexity. We’ll add these two characters in a character class, meaning that we’ll allow either of them at this location.

/\d+[.,]/Edit with Regexity

Note that characters inside a character class are matched literally and therefore the wildcard character .Edit with Regexity does not need to be escaped.

The decimal symbol is followed by two digits from 0 to 9. For this another digit character set \dEdit with Regexity can be used, along with a bounded quantifier {0,2}Edit with Regexity, indicating that we can match either 0, 1, or 2 digits at this location.

/\d+[.,]\d{0,2}/Edit with Regexity

You can adjust this bounded quantifier as you see fit. For example, {2}Edit with Regexity will match exactly 2 decimal digits and nothing else (e.g. 1.99Edit with Regexity). The quantifier {1,2}Edit with Regexity will also match single digit decimal values such as 1.9Edit with Regexity although these are less common. Finally, {0,2}Edit with Regexity will match all of the above as well as zero digits after the decimal (e.g. 1.Edit with Regexity).

The expression above requires that a decimal digit is in place for the match to be successful. In order to include prices such as 100Edit with Regexity without any decimal symbol, we must make the decimal symbol and decimal digits optional. To do this, we can include these in a non-capture group (?:)Edit with Regexity and use a zero-or-one ?Edit with Regexity quantifier behind it to indicate that the entire contents of the non-capture group are optional.

/\d+(?:[.,]\d{0,2})?/Edit with Regexity

Matching a Preceding Currency Symbol

A preceding currency symbol can be included in the expression above if you’d like to include this in your match. This will ensure that you match only prices without matching any similarly non-price values.

For example, to match a dollar symbol $Edit with Regexity before the price, use the following expression:

/\$\d+(?:[.,]\d{0,2})?/Edit with Regexity

Note that the dollar symbol refers to a start-of-string anchor in regex, and must therefore be escaped using a backslash, e.g. \$Edit with Regexity.

Sometimes people choose to include a space between the currency symbol and the actual value. So to include an optional space here, we can add the octal code for a space \x20Edit with Regexity and also follow it with a zero-or-one quantifier ?Edit with Regexity to make it optional:

/\$\x20?\d+(?:[.,]\d{0,2})?/Edit with Regexity

If you’d like to match a list of possible currency symbols you can include this inside a character class at the start of the expression. So to match Dollar $, Euro €, Pound £, and Yen ¥, use the following expression:

/[$€£¥]\x20?\d+(?:[.,]\d{0,2})?/Edit with Regexity

Matching a Succeeding Currency Code e.g. USD

Some currencies don’t use common characters and therefore it is sometimes customary to use a 3-letter currency code behind the price value e.g. 3.99 USDEdit with Regexity.

To match the currency code, we’ll make use of a character class that will allow lowercase a-zEdit with Regexity and uppercase A-ZEdit with Regexity and alphabetic characters, and follow it with a specific quantifier {3}Edit with Regexity to indicate that we’d like to match exactly 3 of these characters:

/\d+[.,]\d{0,2}[a-zA-Z]{3}/Edit with Regexity

To include an optional space between the currency code and the actual value, we can once again include the octal code for a space, followed by a zero-or-one quantifier ?Edit with Regexity to indicate that it is optional:

/\d+[.,]\d{0,2}\x20?[a-zA-Z]{3}/Edit with Regexity

Matching a Thousand’s Separator

Larger values in excess of 1000 might sometimes include a thousand’s separator to make the number easier to read. This separator is usually in the form of a comma ,Edit with Regexity but might also be in the form of a space Edit with Regexity.

To match one of these, let’s first build the section before the decimal point, and later merge it with our existing expressions that cover the part after the decimal point.

A number like this will always start with one, two, or three digits before any thousand’s separator is encountered. So we can use a digit character set \dEdit with Regexity and a quantifier that will allow between one and three characters:

/\d{1,3}/Edit with Regexity

Numbers larger than these will always have one or more instances of a thousand’s separator and three digits, following the first one to three digits. So to match these we use a character class to match either a space or a comma [ ,]Edit with Regexity, and then followed by a digit character set \dEdit with Regexity and a quantifier allowing exactly 3 digits:

/\d{1,3}[ ,]\d{3}/Edit with Regexity

However, the one above will only match one thousand’s separator with the three digits following directly after it. To match more instances, we can wrap this part of the expression in a non-capture group and use a zero-or-more quantifier *Edit with Regexity to indicate that we’ll accept zero or more matches.

/\d{1,3}(?:[ ,]\d{3})*/Edit with Regexity

The final step that remains is to merge this with another expression that covers the part following the decimal symbol. However, to avoid confusion and wrong matches, it’s better to split this up into two groups based on separators.

One group uses a period as a decimal symbol and a comma as a thousand’s separator:

/\d{1,3}(?:[,]\d{3})*(?:[.]\d{0,2})?/Edit with Regexity

The other uses a comma as a decimal symbol and a space as a thousand’s separator.

/\d{1,3}(?:[ ]\d{3})*(?:[,]\d{0,2})?/Edit with Regexity

You can choose the one that works for your use case, or simply combine them with an alternation symbol, showing that we’ll accept either one format or the other.

/\d{1,3}(?:[,]\d{3})*(?:[.]\d{0,2})?|\d{1,3}(?:[ ]\d{3})*(?:[,]\d{0,2})?/Edit with Regexity

Sources

The regular expressions on this page were adapted from a solution presented on Stack Overflow, posted by various users on this question.

Benjamin

Founder, owner, and sole content creator on RegexLand. Enjoys programming, blogging, and teaching others how to do the same. Read more...

Leave a Comment