Currency Regular Expression

前端 未结 3 1522
执念已碎
执念已碎 2020-12-06 08:13

I think I created a working regular expression for what I need. Just wondering if anyone can break it or see a shorter way to write it.

The regular expression shoul

相关标签:
3条回答
  • 2020-12-06 09:04

    Given your examples, the following regular expression will work:

    /^(\$?(?(?=\()(\())\d+(?:,\d+)?(?:\.\d+)?(?(2)\)))$/gm
    

    (note: flags and delimiters are language dependent)

    This regex sets an unnecessary backreference merely to save regex-length. You can ignore the second backreference. If this is intolerable the expression will become quite a bit longer.

    Have a look here: http://regex101.com/r/fH3lV1

    0 讨论(0)
  • 2020-12-06 09:07

    Here is one shorter alternative (56 chars to your 114), which will work in almost all regex flavors:

    ^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}(,?\d{3})?(\.\d\d?)?\)?$
    

    Example: http://www.rubular.com/r/qtYHEVzVK7

    Explanation:

    ^                # start of string anchor
    \$?              # optional '$'
    (?=              # only match if inner regex can match (lookahead)
       \(.*\)          # both '(' and ')' are present
       |               # OR
       [^()]*$         # niether '(' or ')' are present
    )                # end of lookaheand
    \(?              # optional '('
    \d{1,3}          # match 1 to 3 digits
    (,?\d{3})?       # optionally match another 3 digits, preceeded by an optional ','
    (\.\d\d?)?       # optionally match '.' followed by 1 or 2 digits
    \)?              # optional ')'
    $                # end of string anchor
    
    0 讨论(0)
  • 2020-12-06 09:08

    You can express "between one and six digits; comma before the last three digits is optional" a bit more tersely as \d{1,3}(,?\d{3})?. This also allows you to include only two copies of (\.\d{1,2})?: one for positive and one for negative, instead of one for positive-without-comma, one for positive-with-comma, etc.

    Also, \d{1,2} can be shortened slightly to \d\d?, though I'm not sure if that's an improvement.

    So, barring some notation like (?(1)) to test if a backreference is set, here's the shortest version I see:

    ^(\$?\d{1,3}(,?\d{3})?(\.\d\d?)?|\(\$?\d{1,3}(,?\d{3})?(\.\d\d?)?\))$
    

    One perhaps-undesirable aspect of your regex, and of this one, is that they will allow something like $00,012.7, even though no one uses leading zeroes that way. You can address that by requiring the first digit to be nonzero, and then adding a special case to handle $0 and (0.12) and so on:

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

    Edited to add: using a lookahead assertion like F.J suggests in his/her answer, the latter can be shortened to:

    ^(?!\(.*[^)]$|[^(].*\)$)\(?\$?(0|[1-9]\d{0,2}(,?\d{3})?)(\.\d\d?)?\)?$
    
    0 讨论(0)
提交回复
热议问题