Python 正则表达式匹配带/不带逗号或小数点的货币金额

3
如何编写正则表达式,以便1.匹配可能包含逗号或小数点的货币和2.仅匹配货币代码。目前我看到的大多数是匹配货币符号的。
我想能够从完整的文本中匹配货币['300,000.00']和货币代码['USD'],例如: Userid 9XXXX219 sales USD300,000.00 On 01-JUL-2016 08:34:32 到目前为止,我尝试了这个正则表达式,但它只匹配带小数点的货币,而不是没有小数点或带逗号的货币:
s = 'USD1 USD1.00 USD100.00 USD1,000 CAD1,000.00'
re.findall(r'\d+\.\d+', s)
#matches
['1.00', '100.00', '000.00']

#should not match any other thing e.g. 1XXXX324

#instead of this:
['1','1.00', '100.00', '1,000', '1,000.00']

如何编写另一个正则表达式模式来仅匹配货币代码?即:

['USD', 'USD', 'USD', 'USD','CAD'] 

re.compile('(\d+(?:[\.,]\d+)?)') 已经工作 - 快来验证! - Devi Prasad Khatua
@wolframalpha可以匹配有或没有小数点的数字,但无法匹配逗号,例如1,000.00 - DougKruger
re.compile('(\d+(?:[.,]\d+)*)') 如果你想要多个逗号和小数点!! - Devi Prasad Khatua
re.compile('(\d+(?:,\d+)*(?:\.\d+)?)') 如果你想要多个逗号和单个小数点(这更有意义)。 - Devi Prasad Khatua
@wolframalpha 抱歉,这个也将 1XXXX324 匹配为 ['1', '324'],能否去除与货币不同的任何其他内容? - DougKruger
3个回答

4

获取货币:

拥有完整的有效货币列表可能不可行,但如果货币数量有限,则可以按如下方式处理:

re.findall('USD|CAD','USD1 USD1.00 USD100.00 USD1,000 CAD1,000.00 123XXX123')

输出:

['美元', '美元', '美元', '美元', '加元']

获取金额:

使用捕获组,re.findall 将返回每个捕获的 tuple。使用非捕获组 (?:) 将解决此问题。

re.findall('(?<=USD|CAD)\d{1,3}(?:,\d{3})*(?:\.\d+)?(?=\s)','Userid 9XXXX219 sales USD300,000.00 On 01-JUL-2016 08:34:32')

输出:

['300,000.00']

通过示例文本说明:


注意:本文中出现的所有HTML标签需保留。
re.findall('(?<=USD|CAD)\d{1,3}(?:,\d{3})*(?:\.\d+)?(?=\s)','USD1 USD1.00 USD100.00 USD1,000 CAD1,000.00 123XXX123')

输出:

['1', '1.00', '100.00', '1,000', '1,000.00']

在这里阅读更多有关正则表达式的先行断言和后行断言的信息:

(?=) - 正向先行断言 (?<=) - 正向后行断言


谢谢,但与其将两个模式放在一起,是否可能将它们拆分为两个不同的模式,其中一个匹配货币代码,另一个匹配货币。我注意到没有 (?:USD|CAD) 它会将 1XXXX324 匹配为 ['1', '324'] - DougKruger
@KrugerBr,可以做到。就像你尝试过的那样,分割正则表达式。你能否编辑问题并发布实际文本,从中获取这些结果?因为找到一个满足所有条件的理想正则表达式太复杂了。 - gaganso
@KrugerBr,请检查并让我知道是否正常工作。如果这个答案有帮助,请点赞。如果它解决了你的问题,请点击上下箭头下面的勾选标记接受答案。 - gaganso
我的问题中的例子“'Userid 9XXXX219 sales USD300,000.00 On 01-JUL-2016 08:34:32'”匹配的是['219', '300,000.00', '016'],而不仅仅是['300,000.00'] - DougKruger
我已更新例子为“Userid 9XXXX219 销售额为 USD300,000.00,在2016年7月1日08:34:32” - DougKruger
让我们在聊天中继续这个讨论 - DougKruger

1
"

'\d+([.,]?\d*)*'应该匹配所有情况。如果需要,您也可以添加空格。就像这样:

"
'\d+([., ]?\d*)*' 

对于货币代码,'[A-Z]{3}' 应该有效。

P.S. 根据SilentMonk的建议,非捕获组应该使用:

(?:[A-Z]{3})(?:\d+(?:[.,]?\d*)*)

1
只有当您确定 OP 只需要这两种货币时才使用。考虑到全球货币列表可能每天都在增长,明天可能会有一种有效的货币 ABC,所以不要感到惊讶。 - Maria Ivanova
是的,让我们看看原帖需要什么。 - gaganso
根据区域设置,它可能是一个有效的数字(100万)。虽然通常数字会以3位分隔,但这是适用于 OP 的最简单的正则表达式。我们可以尽情改进它并使其更加复杂。 :) 我认为还有更好的选择。 - Maria Ivanova
re.findall(r'(\d+([., ]?\d*)*)', s)如何返回列表而不是元组? [('1 ', ''), ('1.00 ', ''), ('100.00 ', ''), ('1,000 ', ''), ('1,000.00', '')] 如何将其返回为列表? - DougKruger
@KrugerBr,你需要使用非捕获组。请看我的回答。 - gaganso
显示剩余2条评论

1

要匹配货币,只能使用:(\d[0-9,.]+)

要匹配货币代码,可以使用:([A-Z]+)

演示和解释


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接