2

I'm looking for a way to construct a RegExp object from a user input value that will match against some values which contains a dollar character $ (currency).

As I know this character must be escaped I have issues getting it to work correctly, especially in combination with other operators and characters.

I'm looking for to construct a RegExp that will work based on user input and hence it needs to be dynamic. Trying try to explain the scenario, something in this fashion:

User input: "$50" or "50"

"$50" // match
"$50 + $5" // match as it matches on "$50"
"$500 + $50" // match as it matches on "$50"
"$500" // should not match
"$5000" // should not match
"$5.50" // should not match

user input: "$5000" or "5000"

"$5000" // match
"$5,000" // match as it resembles the same value
"$5000 + $500" // match
"$5.000" // should not match
"$5000.50" // should not match

So basically it should only match the exact user input, with the exception of the dollar character ($), if there's a value that follows it but they are separated by a plus symbol (but still the same string), or if the value has a comma which is commonly used when writing larger numbers (for example 5,000).

Is this possible with a RegExp object?

nikkop
  • 63
  • 8
  • Threw us a curveball with the second set of examples, where commas should be matched... – T.J. Crowder Mar 30 '17 at 11:13
  • @T.J.Crowder Is it a lot easier and doable if not having to account for the case with the comma ($5,000)? If so, I think I can settle with not needing to match on that. Thanks – nikkop Mar 30 '17 at 11:17

4 Answers4

0

First, we have to prep the user input a bit — remove the $ if present, and add the beginnings of our regex to allow an optional comma in appropriate thousands places. I've broken out the individual steps, though of course they could be combined:

var userInput = "$5000";
var userInputWithoutDollar = userInput.replace(/^\$/, "");
var userInputWithOptionalCommas = userInputWithoutDollar.replace(/\B(?=(\d{3})+(?!\d))/g, ",?");

That last bit is a variation on this answer for adding commas as thousands separators to a number.

Then, we build our regular expression, remembering that when we're building regular expressions with string literals, we have to double-escape (since backslashes are meaningful both in the string literal and at the regular expression level):

  var rex = new RegExp("(?:^|[^.,\\d])((?:\\$?)" + userInputWithOptionalCommas + ")(?=$|[^.,\\d])");

That says:

  • Beginning of string or a character that isn't ., ,, or a digit
  • Find our number with optional commas
  • And ensure it isn't followed by a ., ,, or digit

The matched text is the first capture group.

Example w/tests:

runTests("$5000", [
    {result: true, value: "$5000"}, // match
    {result: true, value: "$5,000"}, // match as it resembles the same value
    {result: true, value: "$5000 + $500"}, // match
    {result: true, value: "$500 + $5000"}, // match
    {result: false, value: "$5.000"}, // should not match
    {result: false, value: "$5000.50"} // should not match
]);
runTests("500", [
    {result: true, value: "$500"},
    {result: true, value: "$500"},
    {result: false, value: "$1,500"},
    {result: false, value: "1,500"}
]);

function runTests(userInput, tests) {
  var userInputWithoutDollar = userInput.replace(/^\$/, "");
  var userInputWithOptionalCommas = userInputWithoutDollar.replace(/\B(?=(\d{3})+(?!\d))/g, ",?");
  var rex = new RegExp("(?:^|[^.,\\d])((?:\\$?)" + userInputWithOptionalCommas + ")(?=$|[^.,\\d])");
  tests.forEach(function(test) {
      var match = rex.exec(test.value);
      var result = !!match;
      console.log(
          (result == test.result ? "GOOD" : "ERROR") +
          " - Value '" + test.value + "' " +
          (result ? "Matches, got '" + match[1] + "'" : "Doesn't match")
      );
  });
}
.as-console-wrapper {
  max-height: 100% !important;
}
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks for the code, but unfortunately it doesn't seem to behave as needed. Using "$500" as input will match on "$5000", which is not desirable. Is this possible to fix? – nikkop Mar 30 '17 at 13:04
  • @nikkop: I forgot to escape a backslash in one place (darned string literals). Fixed above. It had `+ "(?=$|[^.\d])"` where it wanted `+ "(?=$|[^.\\d])"` – T.J. Crowder Mar 30 '17 at 13:08
  • Thanks, I changed into that and that part works as expected. However, when inputting for example "$500", it will also match on "$1,500", "$2,500" etc. Is this possible to fix as well? Sorry for not including this in my first post of non-desirable matches. – nikkop Mar 30 '17 at 13:19
  • Removing `\\b` from `(?:^|^\\$|\\b|\\$)` seems to work, but I'm not sure if I miss out on anything else then or alter any behaviour. Is this the proper way to fix the issue? Thanks – nikkop Mar 30 '17 at 13:43
  • @nikkop: Sorry about 500 matching $1,500. To handle that in JavaScript, sadly, we need to use a capture group as JavaScript doesn't have lookbehind. I've updated to show that. – T.J. Crowder Mar 30 '17 at 14:37
  • for input = 5000, `(?:^|\b)\$?5,?000(?=\s|$)` have any problem? in other word, why should use `(?:^|[^.,\\d])(?:\\$?)` in the beginning and `(?=$|[^.,\\d])` at the end of pattern @nikkop – MohaMad Mar 31 '17 at 08:39
-1

Version 1

Except the example with comma, the following Regex meets your requirement:

(?:\$?)\$5000(?:$|\s.*)

Remember to escape the $ in $5000

Explanation

(?:\$?): Match a single $ sign if present, the ? indicates occurrence of $ to be 1 or 0.

\$5000: It is the input with $ escaped.

(?:$|\s.*): Matches either the end of a string or anything after a space.


Version 2

Again, comma is not accommodated.

(?:\$?)\$50(?:$|(?:\s(?:\+|\-)\s(?:\$?)(?:[0-9]+))+)

Explanation

(?:\$?): Match a single $ sign if present, the ? indicates occurrence of $ to be 1 or 0.

\$5000: It is the input with $ escaped.

(?:$|(?:\s(?:\+|\-)\s(?:\$?)(?:[0-9]+))+): Matches either end of string or + $xxx or - $xxx after the match, even if they are repeated.

Community
  • 1
  • 1
Ali Yousuf
  • 692
  • 8
  • 23
-1

Converting $ to \$ and adding ,? to userInput value, makes regex pattern

var userInput = "500000000" ;
if(userInput.substring(0,1) != "$"){userInput = "$"+userInput ;}
var c = userInput.length-2;
for(var i = Math.floor(c/3)*3 ; i>0 ; i-=3){
  userInput = userInput.substring(0,userInput.length-i) + ",?" + userInput.substr(-i) ;
}
userInput = "(?:^|\\b)" + userInput.replace("$","\\\$\?") + "(?=\\s|$)" ;

for 5000, out put is:

\$?5,?000
//updated to
(?:^|\b)\$?5,?000(?=\s|$)

see Demo

Updates done:

  • Changed (?:..) to (?=..) to stop matching after found number

  • missed assign of replacing of "$" with "\$?" to userInput

MohaMad
  • 2,575
  • 2
  • 14
  • 26
-2

 var regExp = /^\$(50*)|(\+50*)/igm ;
    console.log(regExp.test("$50")); //true
    console.log(regExp.test("$50000")); //true
    console.log(regExp.test("$50+50")); //true
    console.log(regExp.test("$50+500000")); //true
    console.log(regExp.test("$50.00")); //false
    console.log(regExp.test("$50.00+50")); //false
prasanth
  • 22,145
  • 4
  • 29
  • 53
  • Unfortunately it doesn't seem to behave as expected as it doesn't return what you have commented it should return. – nikkop Mar 30 '17 at 13:06