我正在寻找一个正则表达式,它将从字符串中提取所有可能的金额,假设金额始终包含 2 个小数,并接受 .
或 ,
自由地作为分隔符。例如,对于以下字符串,我想找到以下金额:
1.234,567.89
1.23
1.234,56
234,56
34,56
4,56
1.234,567.89
234,567.89
34,567.89
4,567.89
567.89
67.89
7.89
这可以用正则表达式实现吗?
我当前的正则表达式是 ?\\d{1,3}([\\.,]\\d{3})*([\\.,]\\d{2})
但这显然不起作用,因为它只返回 1 个匹配项。
最佳答案
所以,最初,我认为这不能用正则表达式来完成。我的假设是错误的,但这只能通过删除重复项和空字符串/空值来实现。
正则表达式
(?=(\d+[.,]\d{2}))(?=((?:\d+[.,]){2,}?\d{2})?)(?=((?:\d+[.,])+\d{2}))
上面的模式包含 3 个正面前瞻。它们如下:
(?=(\d+[.,]\d{2}))
确保以下匹配(\d+[.,]\d{2})
将以下内容捕获到捕获组 1 中。这会捕获较短的变体,例如1.23
。\d+
匹配一个或多个数字[.,]
按字面匹配.
或,
\d{2}
正好匹配 2 个数字
(?=((?:\d+[.,]){2,}?\d{2})?)
确保以下匹配((?:\d+[.,]){2,}?\d{2})?
可选择将以下内容捕获到捕获组 2 中。这会捕获 in-在 数字之间,例如1.234,56
,其中在同一位置存在较小版本和较长版本(分别为1.23
和1.234,567.89
).如果可能有更长的数字版本,您可能需要添加更多与此相同的正面前瞻,并将下一节中的{2,}
更改为{3,}
,{4,}
等并将这些组添加到while
循环中。如果不存在 in-between 数字,它将简单地捕获与第三个 lookahead 相同的数字(代码中删除了重复项)。(?:\d+[.,]){2,}?
匹配以下 2 次或更多次,但尽可能少。\d+
匹配一个或多个数字[.,]
按字面匹配.
或,
\d{2}
正好匹配 2 个数字
(?=((?:\d+[.,])+\d{2}))
确保以下匹配((?:\d+[.,])+\d{2})
将以下内容捕获到捕获组 3 中。这会捕获更长的变体,例如1.234,567.89
。(?:\d+[.,])+
匹配以下一次或多次\d+
匹配一个或多个数字[.,]
按字面匹配.
或,
\d{2}
正好匹配 2 个数字
代码
下面的代码简单地遍历所有匹配项并提取组值,将它们添加到 List
中。然后使用找到的方法从列表中删除 null
值 here .然后根据 this answer 将该列表变成 Set
以删除重复项。并添加回(现在为空)列表。
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Main{
public static void main(String[] args) {
String s = "1.234,567.89";
Pattern p = Pattern.compile("(?=(\\d+[.,]\\d{2}))(?=((?:\\d+[.,]){2,}?\\d{2})?)(?=((?:\\d+[.,])+\\d{2}))");
Matcher m = p.matcher(s);
List<String> al = new ArrayList<>();
Set<String> hs = new HashSet<>();
while(m.find()) {
al.add(m.group(1));
al.add(m.group(2));
al.add(m.group(3));
}
al.removeAll(Collections.singleton(null));
hs.addAll(al);
al.clear();
al.addAll(hs);
System.out.println(al);
}
}
结果
下面结果中的数字与 OP 的值列表一致(尽管输出看起来不同,但您可以通过交叉检查两组值来确认)。
[34,567.89, 4,56, 7.89, 234,56, 4,567.89, 1.234,56, 1.23, 1.234,567.89, 34,56, 567.89, 67.89, 234,567.89]
关于java - 用于提取所有可能金额的正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49925964/