【问题标题】:What is "The Best" U.S. Currency RegEx?什么是“最好的”美国货币 RegEx?
【发布时间】:2010-09-26 03:00:32
【问题描述】:

快速搜索货币正则表达式会弹出a lot of results

我在选择一个时遇到的问题是,如果不测试所有边缘情况,就很难验证正则表达式。是否有人拥有经过彻底测试的美元正则表达式?

我唯一的要求是匹配的字符串是美国货币并解析为System.Decimal

[ws][sign][digits,]digits[.fractional-digits][ws] 方括号([ 和 ])中的元素是可选的。 下表描述了每个元素。 元素描述 ws 可选的空格。 标志 可选标志。 数字 范围从 0 到 9 的数字序列。 , 特定于文化的千位分隔符。 .特定于文化的小数点符号。 小数位数 范围从 0 到 9 的数字序列。

【问题讨论】:

  • 我会再添加一个潜在问题 - 使用括号代替符号。这是会计中相当普遍的惯例。
  • 您引用的MSDN 允许00000000042。呜呜。

标签: regex currency


【解决方案1】:

这里有一些来自 Regex Buddy 制造商的东西。这些来自图书馆,所以我相信它们已经过彻底的测试。

数字:货币金额(必须为美分) 可选的千位分隔符;强制两位小数

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

数字:货币金额(美分可选) 可选的千位分隔符;可选的两位小数

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

数字:货币金额美国和欧盟(美分可选) 可以使用美式 123,456.78 表示法和欧式 123.456,78 表示法。可选的千位分隔符;可选的两位小数

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

【讨论】:

  • 现在已经很老了,但是这个正则表达式不能很好地处理可选逗号。数字11111111,111,111111.11 显然格式不正确,但这个正则表达式会匹配它。
  • @Keng,我同意它满足 OP 的需求,只是做笔记,因为这是一个名为 What is “The Best” U.S. Currency RegEx 的问题的答案
  • 我认为我们可以通过将 (?:,?[0-9]{3})* 替换为 (?:(,[0-9]{3})*|([0-9]{3})*) 来解决可选逗号问题。逗号无处不在或没有逗号。
  • 这个答案将通过正则表达式上方的示例数字来改进,而不是(或以及)单词描述。
  • @Keng 现在是 2020 年,我仍然在乎 - 正则表达式不会像牛奶一样过期。
【解决方案2】:

我在 www.RegExLib.com 的 Kirk Fuller, Gregg Durishan 上在线找到了这个正则表达式

过去几年我一直在成功使用它。

"^\$?\-?([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}))\)$"

【讨论】:

  • 虽然我的测试不是权威的,但这个对我有用。接受:123 123.00 $123.00 1234 $1234 $1234.00 $1,234.00 拒绝:#123 1,2,34 我发现唯一的问题是它接受了 123.4
  • 工作,工作的人想要 123.4 作为有效的美元金额。
  • 就是这样
  • 如何在 javascript 中运行它?
  • 就我而言,123.4 很好 - 如果人们不知道如何正确从 Excel 导出,他们可能会导出 123.4 而不是 0.40,而且我发现 Tabula 有时会漏掉某些导入的最后一位数字。就是这样。
【解决方案3】:

根本没有经过彻底测试(我只是写了它!),但似乎表现正确:

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

测试集:

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

注意:您的 System.Decimal 取决于语言环境,很难在正则表达式中制作,除非在构建它时。我假设数字按三分组,即使在某些文化(语言环境)中存在不同的规则。
在它周围添加空格是微不足道的。

【讨论】:

  • @RonRoyston 最初的问题要求数字出现在小数点之前...(请参阅错误测试集中的 .10 案例)。 0.75 确实通过了,当我转到 regex101.com 时,粘贴我的表达式并添加你的两个案例。
【解决方案4】:

如果您想考虑人为错误,您可以在匹配货币时使正则表达式更加宽容。我使用了 Keng 的第二个不错的正则表达式,并使它更健壮地解决了拼写错误。

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

这将匹配任何这些正确或损坏的货币数字,但不会在空格后面拾取多余的垃圾:

$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

【讨论】:

    【解决方案5】:

    Keng 的答案很完美,我只想补充一点,以使用 1 位或 2 位小数(第三版):

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

    网络提琴: https://dotnetfiddle.net/1mUpX2

    【讨论】:

      【解决方案6】:

      这个问题已经有几年了,所以我想给出一个更新的答案。

      我使用过jQuery InputMask,它在输入/格式屏蔽(例如电话号码等)方面效果很好,但根据我的经验,它对货币的效果并不好。

      对于货币,我强烈推荐autoNumeric jQuery 插件。它维护得很好,他们基本上“想到了一切”我想要的货币。

      我实际上结合使用这两个插件来格式化电话号码、数字格式(ISBN 等)以及货币(主要是美元)。

      请记住,jquery.inputmask 主要是关于控制值的格式,而autoNumeric 是关于专门控制货币的格式。

      【讨论】:

      • 确实,仅尝试使用正则表达式只会让您感到痛苦和绝望。查看 AutoNumeric 代码行数(截至今天):~/dev/autoNumeric » cat src/*|wc -l -> 10851。这只是当今用于格式化货币的最完整的库,并且确实经过彻底测试 ;) (免责声明;我是它的维护者之一)
      • 你能举个例子,使用这个库从字符串中提取货币值吗?
      • @Ari:这些库更多的是在用户将数据输入到输入字段时控制数据的格式;我不使用它们从字符串中提取货币。要从字符串中提取货币,您可以使用正则表达式删除任何不是 0-9 和小数的内容,然后将其转换为浮点数,然后我建议将货币值作为美分存储在数据库中。未经测试的伪代码:"$123,456.78".gsub(/^[0-9]\./, "").to_f => 123456.78(请注意,这允许多个小数位,但要证明浓度)。
      【解决方案7】:

      /^[-]?[$]\d{1,3}(?:,?\d{3})*\.\d{2}$/ 是我想出的 - 我看到了类似的答案,但我只是使用了 \d 而不是 [0-9]

      【讨论】:

      • 这个截图出自哪里?
      【解决方案8】:

      我正在使用以下正则表达式进行货币验证:

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

      您还可以允许可选的前导美元符号:

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

      您可以通过添加轻松添加括号测试而不是符号

      \( and \)
      

      【讨论】:

        【解决方案9】:

        我也在研究这个问题,并得出结论,最好根据当前文化构建正则表达式。 我们可以使用

        CurrencyPositivePattern 
        CurrencyGroupSeparator
        CurrencyDecimalSeparator
        

        NumberFormatInfo 的属性以获取所需的格式。

        编辑:像这样

        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 : ""); 
        

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

        【讨论】:

        • @Robert-levy:添加参考 msdn.microsoft.com/en-us/library/hs600312.aspx
        • 这可能会通过说它是用于 c# 来改进
        【解决方案10】:

        我在这方面取得了成功(从上面的一些正则表达式中获取点点滴滴)。最多只能处理数千个,但扩展它应该不会太难

        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)
        }
        

        【讨论】:

          【解决方案11】:

          这是我用的:

          没有前导 + 或 -

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

          带有可选的前导 + 或 -

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

          网络小提琴: https://jsfiddle.net/compsult/9of63cwk/12/

          【讨论】:

            【解决方案12】:

            使用 Leandro 的答案,我在开头添加了 ^(?:[$]|) 以允许前面的美元符号

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

            这个匹配

            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
            

            不匹配

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

            【讨论】:

              【解决方案13】:

              这个呢?更短更优雅

              (?:\,|\.?\d)*
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-09-29
                • 2019-06-20
                • 1970-01-01
                • 2020-05-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多