Java,Regex匹配String中的前10位数,忽略前导零

Mic*_*ael 2 java regex

我有兴趣从长字符串中提取前10个数字而忽略前导零.此外,如果只有零,则只返回1 0,如果没有数字,则返回空字符串.我希望将它与一个匹配find.

例如:

  • "abcd00111.g2012asd" 应该匹配 "1112012"
  • "aktr0011122222222222ddd" 应该匹配 "1112222222"
  • "asdas000000asdasds0000" 应该匹配 "0"
  • "adsads.cxzv.;asdasd" 应该匹配 ""

这是我到目前为止所尝试的:Ideone演示 - 代码

Pattern p = Pattern.compile("[1-9]{1}+[0-9]{9}");
Matcher m = p.matcher(str);
if (m.find()) {
  String match = m.group();
  System.out.println(match);
}
Run Code Online (Sandbox Code Playgroud)

问题是这个正则表达式在第一个非零之后需要9个连续数字,我需要任何9位数(其间可能是非数字字符).

请注意,在我的代码中,if (m.find())而不是while (m.find())因为我希望在单次运行中找到匹配.

UPDATE

基于评论我明白,正则表达式不可能在单次运行中完成.

我想答案不一定是基于正则表达式,但最有效率,因为我将多次执行此方法.

nha*_*tdh 5

一般情况下,不可能单独使用它find.如果您知道连续数字序列的最大数量,则可以执行此操作,但如果不知道,则不可能,至少在Java Pattern类的支持级别.我错了.Kobi的评论显示,单个正则表达式是可能的.我将在这里重现评论:

哦,通过捕获10个数字中的每一个,有点像这样的东西^[\D0]*(\d)\D*(?:(\d)\D*(?:(\d)\D*(?:(\d)\D*(?#{6 more times}))?)?)?,它有点可能,但它真的很难看,并且不能很好地扩展.

但是,您仍然需要连接组.开头的正则表达式中的逻辑是非常好的:由于贪婪的属性,它将搜索在所有前导零之后的第一个非零数字(如果有的话),或者如果没有非零,它将采用最后的0 - 零数字.


如果你把关于效率的讨论扔出门外,你想要短代码:

String digitOnly = str.replaceAll("\\D+", "");
String noLeadingZero = digitOnly.replaceFirst("^0+", "");
String result = digitOnly.isEmpty() ? "" :
                noLeadingZero.isEmpty() ? "0" : 
                noLeadingZero.substring(0, Math.min(noLeadingZero.length(), 10));
Run Code Online (Sandbox Code Playgroud)

坦率地说,循环通过字符串,有一个StringBuilder足够好,它应该比正则表达式解决方案更快.

StringBuilder output = new StringBuilder();
boolean hasDigit = false;
boolean leadingZero = true;
for (int i = 0; i < str.length() && output.length() < 10; i++) {
    char currChar = str.charAt(i);
    if ('0' <= currChar && currChar <= '9') {
        hasDigit = true;
        if (currChar != '0') {
            output.append(currChar);
            leadingZero = false;
        } else if (!leadingZero) { // currChar == 0
            output.append(currChar);
        } // Ignore leading zero
    }
}

String result = !hasDigit ? "" :
                output.length() == 0 ? "0" :
                output.toString();
Run Code Online (Sandbox Code Playgroud)

性能测试代码.请注意,您应该调整参数以使其类似于实际输入,以便获得良好的近似值.我怀疑循环方法比涉及正则表达式的任何东西慢; 然而,差异仅在大规模上显着.