我有兴趣从长字符串中提取前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())
,因为我希望在单次运行中找到匹配项。
更新
基于我所理解的评论,正则表达式无法在单次运行中完成。
我希望答案不一定是基于正则表达式,但最有效率,因为我会多次执行此方法。
答案 0 :(得分:5)
一般情况下,单个 I这是错的。 Kobi's comment表明可以使用单个正则表达式。我将在此重现评论:find
无法做到这一点。如果您知道连续数字序列的最大数量,则可以执行此操作,但如果不知道,那么这是不可能的,至少在Java Pattern
类的支持级别上是不可能的。
哦,通过捕获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