提问人:Henley Wing Chiu 提问时间:9/6/2023 最后编辑:MarkHenley Wing Chiu 更新时间:9/9/2023 访问量:101
正则表达式从包含数字的字符串中提取数字
Regex to extract number from a string with numbers
问:
我想要一个正则表达式从至少有一个数字的字符串中提取第一个数字(假设 . 代表十进制,而 , 代表分隔千位)
examples = ["I earned $100,000", "I earned $100000", "I earned $100000.05"]
desired_output = ["100000", "100000", "100000.05"]
这是我尝试过的正则表达式:
regex = /((\d{1,3}(?:,\d{3})*)(?:\.(\d{0,2}))?)/
但是,对于字符串“I earned $100000”,它提取“100”,而不是“100000”。
regex.match("I earned $100000") #returns 100
如何修改此正则表达式?
答:
您应该首先匹配整个文本,然后删除不需要的分隔符。
模式:["100,000","100000","100000.5"]
[\d\,\.]+
您的正则表达式模式仅匹配 100,因为您将 000 保留在未捕获的组中
examples = ["I earned $100,000", "I earned $100000", "I earned $100000.05"]
法典
p examples.map { |string| /\$([\d,.]+)/.match(string)[1] }
输出
["100,000", "100000", "100000.05"]
评论
{ |string| string[/\$([\d,.]+)/] }
',,,,,,,'
100000
100,000
您可以附加单词边界以防止部分单词匹配,而是匹配 1+ 数字,如果您不需要捕获组,可以省略它们:
\b\d+(?:,\d{3})*(?:\.\d{0,2})?\b
评论
'007'
\b0*(\d+(?:,\d{3})*(?:\.\d{0,2})?)\b
\b[1-9](?:\d{0,2}(?:,\d{3})*|\d*)(?:\.\d{2})?\b
$007.12
2
007
提取美元值,然后验证和转换
假设您始终使用美元而不是其他货币,即使您有一个空的 String 或多个设置的货币值,以下操作也有效。
examples = [
"I earned $100,000", "I earned $100000",
"I earned $100000.05", "",
"I earned $2.50, which is half of $5.00"
]
examples.map { _1.scan(/\$(\d[\d,.]+)\b/).first }
.compact.flatten.map { _1.delete ?, }
#=> ["100000", "100000", "100000.05", "2.50"]
其工作原理是提取所有带有前导美元符号的值,然后操作匹配项。这些步骤包括:
使用 String#scan 捕获以美元符号为前缀并后跟单词边界的所有数字(包括小数和逗号)。
没有努力验证示例集中的边缘情况,例如显式值、格式不正确的值(如 )或负值(如 或 )。
nil
$1.00.2
-$1.00
($5.00)
另外,请注意,前导零或尾随零不一定是错误; 对于某些用例可能完全有效,因此前导零、填充、十进制精度或问题范围之外的其他内容不会得到解决。你可以用更复杂的正则表达式来做很多这样的验证,但我个人认为,你应该在事后验证你的结果,而不是试图在一个单一的正则表达式中完成所有验证,以降低认知负荷。YMMV。
$00.00
如果找到多个美元金额,则仅选择字符串中的第一个美元金额。
从结果中删除任何值。
nil
展平压缩的结果数组。
从扁平化的 String 值数组中删除逗号。
当然有更短的解决方案,并且解决方案将更明确地说明什么是有效的美元金额,但对我来说,扫描只是在概念上似乎更简单。这样一来,您就可以将对格式设置和验证的关注从核心正则表达式中移出。/\$(\d[\d,.]+)\b/
是使用链式方法处理结果集,还是通过对结果调用一系列“清理步骤”来处理结果集,都由您决定。恕我直言,您在正则表达式中所做的工作越少,就越容易调试对您很重要的任何后续转换或验证。
评论