RJK
RJK

Reputation: 242

How to match a cost or price number value only if it features a preceding currency symbol like '$'?

It will cost you $112.52 for 302 pokemon cards to complete this order

It will cost you $112.52 to complete this order

Above are two strings that I want to find the dollar value using regex. Below is my current regex:

const match = str.match(/will cost you \$(.*) for ([0-9]+) pokemon cards to complete this order|will cost you \$(.*) to complete this order/);

I can get $112.52 in match[1] and match[3] for both strings.

However with this way (([0-9]+)), I am also matching the number of pokemon cards 302 which is NOT what I want (in match[2]). Is there a way I can ignore any number of pokemon cards and match just the dollar sign value in both strings in a single regex?

Upvotes: 0

Views: 108

Answers (3)

xkeshav
xkeshav

Reputation: 54016

use lookbehind assertion in regex

(?<=Y)X Positive lookbehind X if after Y

(?<=\$)\d+

example: https://regex101.com/r/H7Iyb6/1

reference: https://javascript.info/regexp-lookahead-lookbehind

other way is that you can use unicode property \p class with \u flag

const regex = \p{Sc}\p{Nd}+.\p{Nd}+

\p example

Upvotes: 0

Peter Seliger
Peter Seliger

Reputation: 13376

A precisely matching regex had to check the validity of a number value as well which follows the leading $. One would achieve this by regex-lookarounds where a negative lookahead would assure a single valid integer or float number value whereas the positive lookbehind would support the direct match of the number value.

Such a regex would be as follows ...

/(?<=\$)(?:\d*\.)?\d+(?![.\d])/g

... and the description is provided by its test/playground page.

Its usage would be as follows ...

const sampleText = `
  It will cost you $112.52 for 302 pokemon cards to complete this order
  It will cost you $.52 for 302 pokemon cards to complete this order

  It will cost you $2.52.523.45 for 302 pokemon cards to complete this order
  It will cost you $.52.523.455 for 302 pokemon cards to complete this order
  It will cost you $ .52 to complete this order

  It will cost you $.52 to complete this order
  It will cost you $112 to complete this order`;

// see ... [https://regex101.com/r/hjIoWb/1]
const regXNumberValue = /(?<=\$)(?:\d*\.)?\d+(?![.\d])/g;

console.log(
  sampleText
    .match(regXNumberValue)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Since lookbehinds are not supported by e.g. even the latest safari versions one has to work around it. A possible solutions was the usage of an e.g. named capturing group.

The above first provided regex then changes to ...

/\$(?<value>(?:\d*\.)?\d+)(?![.\d])/g

... where the pattern gets explained by its test/playground page.

Its usage needs to be changed too, from match to matchAll followed by an additional mapping task ...

const sampleText = `
  It will cost you $112.52 for 302 pokemon cards to complete this order
  It will cost you $.52 for 302 pokemon cards to complete this order

  It will cost you $2.52.523.45 for 302 pokemon cards to complete this order
  It will cost you $.52.523.455 for 302 pokemon cards to complete this order
  It will cost you $ .52 to complete this order

  It will cost you $.52 to complete this order
  It will cost you $112 to complete this order`;

// see ... [https://regex101.com/r/hjIoWb/2]
const regXNumberValue = /\$(?<value>(?:\d*\.)?\d+)(?![.\d])/g;

console.log(
  [...sampleText.matchAll(regXNumberValue)]
    .map(({ groups: { value } }) => value)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Upvotes: 0

MrWedders
MrWedders

Reputation: 156

If you just want the dollar amount and don't care about anything else in the string, you don't need to mention anything else in the string in your regex.

You could just match $ followed by numbers and dots, i.e

str.match(/\$([\d\.]+)/)

A fuller test example...

(function() {
    let strs = [
        "It will cost you $112.52 for 302 pokemon cards to complete this order",
        "It will cost you $112.52 to complete this order"
    ];
    
    strs.forEach(
        (str) => {
            let match = str.match(/\$([\d\.]+)/);
            console.debug(match);
        }
    );
})();

...outputs...

Array [ "$112.52", "112.52" ]
Array [ "$112.52", "112.52" ]

Upvotes: 2

Related Questions