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

时间:2013-02-27 06:35:47

标签: java regex

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

例如:

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

以下是我到目前为止所尝试的内容:Ideone Demo - code

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);
}

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

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

更新

基于我所理解的评论,正则表达式无法在单次运行中完成。

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

2 个答案:

答案 0 :(得分:5)

一般情况下,单个find无法做到这一点。如果您知道连续数字序列的最大数量,则可以执行此操作,但如果不知道,那么这是不可能的,至少在Java Pattern类的支持级别上是不可能的。 I这是错的。 Kobi's comment表明可以使用单个正则表达式。我将在此重现评论:

  

哦,通过捕获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));

坦率地说,使用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();

Performance testing code。请注意,您应该调整参数以使其类似于实际输入,以便获得良好的近似值。我怀疑循环方法比涉及正则表达式的任何东西慢;然而,差异只是大规模的显着。

答案 1 :(得分:2)

String test = "sdfsd0000234.432004gr23.022";
StringBuilder sb = new StringBuilder();
for(int i=0;i<test.length();i++) {
    if(Character.isDigit(test.charAt(i))) 
        sb = sb.append(test.charAt(i));
}
String result = sb.toString();
result = result.replaceFirst("^0*", "");  //Remove leading zeros
System.out.println(result);               //Will print 23443200423022