什么是“最好的”美国货币 RegEx?
Posted
技术标签:
【中文标题】什么是“最好的”美国货币 RegEx?【英文标题】:What is "The Best" U.S. Currency RegEx? 【发布时间】:2010-09-26 03:00:32 【问题描述】:快速搜索货币正则表达式会弹出a lot of results。
我在选择一个时遇到的问题是,如果不测试所有边缘情况,就很难验证正则表达式。是否有人拥有经过彻底测试的美元正则表达式?
我唯一的要求是匹配的字符串是美国货币并解析为System.Decimal
:
【问题讨论】:
我会再添加一个潜在问题 - 使用括号代替符号。这是会计中相当普遍的惯例。 您引用的MSDN
允许00000000042
。呜呜。
【参考方案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(\,\d3)*(\.\d0,2)?|[1-9]1\d0,(\.\d0,2)?|0(\.\d0,2)?|(\.\d1,2))$|^\-?\$?([1-9]1\d0,2(\,\d3)*(\.\d0,2)?|[1-9]1\d0,(\.\d0,2)?|0(\.\d0,2)?|(\.\d1,2))$|^\(\$?([1-9]1\d0,2(\,\d3)*(\.\d0,2)?|[1-9]1\d0,(\.\d0,2)?|0(\.\d0,2)?|(\.\d1,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]\d0,2(?:,?\d3)*)(?:\.\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】:
/^[-]?[$]\d1,3(?:,?\d3)*\.\d2$/
是我想出的 - 我看到了类似的答案,但我只是使用了 \d
而不是 [0-9]
【讨论】:
这个截图出自哪里?【参考方案8】:我正在使用以下正则表达式进行货币验证:
^-?0*(?:\d+(?!,)(?:\.\d1,2)?|(?:\d1,3(?:,\d3)*(?:\.\d1,2)?))$
您还可以允许可选的前导美元符号:
^\$?-?0*(?:\d+(?!,)(?:\.\d1,2)?|(?:\d1,3(?:,\d3)*(?:\.\d1,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 ~> """\d0,2""".r ^^
_.toInt
def dollarAmount: Parser[Int] = """[1-9]1[0-9]0,2""".r ~ opt( """[\.\,]""".r ~> """\d3""".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】:这是我用的:
没有前导 + 或 -
^\$\d1,3\.[0-9]2$|^\$(\d1,3,)+\d3\.[0-9]2$
带有可选的前导 + 或 -
^[+-]?\$\d1,3\.[0-9]2$|^[+-]?\$(\d1,3,)+\d3\.[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)*
【讨论】:
以上是关于什么是“最好的”美国货币 RegEx?的主要内容,如果未能解决你的问题,请参考以下文章