我在寻找一个正则表达式,将提取所有可能的金额从一个字符串,假设数额总是包含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
Run Code Online (Sandbox Code Playgroud)
这是用正则表达式实现的吗?
我当前的正则表达式?\\d{1,3}([\\.,]\\d{3})*([\\.,]\\d{2})但显然不起作用,因为它只返回1个匹配.
所以,最初,我认为这不能用正则表达式完成.我这样做是错误的,但这只能通过删除重复项和空字符串/空来实现.
(?=(\d+[.,]\d{2}))(?=((?:\d+[.,]){2,}?\d{2})?)(?=((?:\d+[.,])+\d{2}))
Run Code Online (Sandbox Code Playgroud)
上面的模式包含3个正向前瞻.它们如下:
(?=(\d+[.,]\d{2})) 确保以下匹配
(\d+[.,]\d{2})将以下内容捕获到捕获组1.这样可以捕获较短的变体1.23.
\d+ 匹配一个或多个数字[.,]匹配.或,字面上\d{2} 正好匹配2位数(?=((?:\d+[.,]){2,}?\d{2})?) 确保以下匹配
((?:\d+[.,]){2,}?\d{2})?(可选)将以下内容捕获到捕获组2.这将捕获中间数字,例如1.234,56较小版本和较长版本存在于同一位置(1.23和1.234,567.89分别).如果再多个版本是可能的,你可能需要添加相同方式分享和改变更积极的向前看符号{2,}在下面的部分{3,},{4,}等等,并添加这些组的while循环.如果不存在中间数字,它将只捕获与第三个前瞻相同的内容(代码中删除了副本).
(?:\d+[.,]){2,}? 匹配以下2次或更多次,但尽可能少.
\d+ 匹配一个或多个数字[.,]匹配.或,字面上\d{2} 正好匹配2位数(?=((?:\d+[.,])+\d{2})) 确保以下匹配
((?:\d+[.,])+\d{2})将以下内容捕获到捕获组3中.这样可以捕获更长的变体1.234,567.89.
(?:\d+[.,])+ 匹配以下一次或多次
\d+ 匹配一个或多个数字[.,]匹配.或,字面上\d{2} 正好匹配2位数下面的代码简单地迭代所有匹配并提取组值将它们添加到a List.null然后使用此处找到的方法从列表中删除值.然后Set根据此答案将列表转换为a 以删除重复项,并将其添加回(现在为空)列表.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
下面结果中的数字与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]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
43 次 |
| 最近记录: |