在Java中提取字符串中的数字

230

我有一个Java String 对象,需要从中提取数字。举个例子:

"123-456-789" 我想要 "123456789"

是否有一个库函数可以提取数字?

感谢回答。在尝试这些方法之前,我需要知道是否需要安装任何额外的库?

15个回答

614
你可以使用正则表达式并删除非数字字符。
str = str.replaceAll("\\D+","");

6
不错的简短代码。线性搜索可能会更快,但我认为你的代码更有意义。 - kasten
23
我猜你可以对任何你喜欢的东西进行踩票(没有讽刺意味)。但我的个人看法是:当众多优秀的开发者(我们这里有很多)免费分享他们的建议时,我会珍视这些建议,只有真的很糟糕的东西我才会踩(查看我的个人资料,我的当前比率为14xx赞同17反对)。但这是我的个人哲学,你可以自由地持有你自己的看法。 - Sean Patrick Floyd
91
如果您的数字有小数点,这种方法就不起作用,因为它也会移除小数点。代码str = str.replaceAll("[^\\.0123456789]",""); - Aravindan R
2
尽管正则表达式非常简单和清晰易懂,但它存在性能问题,只应在需要一次性剥离(例如表单提交)的情况下使用。如果您正在处理大量数据,则不应采用此方法。 - Brill Pappin
2
如果您需要排除任何内容,例如小数点,请使用(?!\\.) - azerafati
显示剩余8条评论

50

这里有一个更冗长的解决方案。不太优雅,但可能更快:

public static String stripNonDigits(
            final CharSequence input /* inspired by seh's comment */){
    final StringBuilder sb = new StringBuilder(
            input.length() /* also inspired by seh's comment */);
    for(int i = 0; i < input.length(); i++){
        final char c = input.charAt(i);
        if(c > 47 && c < 58){
            sb.append(c);
        }
    }
    return sb.toString();
}

测试代码:

public static void main(final String[] args){
    final String input = "0-123-abc-456-xyz-789";
    final String result = stripNonDigits(input);
    System.out.println(result);
}

输出:

0123456789

顺便提一下:我没有使用Character.isDigit(ch),因为它除了0-9之外还接受很多其他字符。


4
为确保StringBuilder不需要重新分配内存,您应该为构造函数提供一个大小(例如input.length())。在此处您不需要要求一个StringCharSequence足够。另外,您可以通过编写一个接受CharSequence作为输入和Appendable实例作为输出累加器的单独函数,将StringBuilder的分配与非数字的收集分离开来。 - seh
1
@seh 听起来很有趣,但与其评论,为什么不使用扩展功能创建自己的答案呢? - RedYeti
4
@RedYeti 让这个回答保留并添加评论是更光荣的,因为Sean得到了赞成票。如果你匆忙时批评别人的代码比重写它要快得多。不要惩罚Seh做出有价值的贡献,他没有必要添加那些有用的信息,你的回应会让他下次不太可能再这么做。 - KomodoDave
2
我并没有“惩罚”任何人——这完全是对我对@seh所说的话的曲解。我的观点是,他的评论增加了很多有价值的内容,实际上改变了很多东西,以至于我觉得它值得有一个独立的回答。我相信Sean Patrick Floyd不仅关心赞誉,更关心帮助他人,他会很高兴看到seh提供自己的答案。我只是在鼓励seh,因为我觉得他的贡献应该得到更大的关注。如果有人把我的评论理解成其他意思,那真是让我困惑了,但如果确实如此,我向seh道歉。 - RedYeti
1
我同意Guava的答案非常简短易读。但是,由于我在自己的工作中没有实际使用Google Guava,所以我更喜欢“纯”的Java答案。我只是想补充一下如何使Java代码更易读的建议。 - Raystorm
显示剩余10条评论

22
public String extractDigits(String src) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < src.length(); i++) {
        char c = src.charAt(i);
        if (Character.isDigit(c)) {
            builder.append(c);
        }
    }
    return builder.toString();
}

我本来想使用Character.isDigit(),但它也接受一些不是0-9的字符(请参见文档:http://download.oracle.com/javase/6/docs/api/java/lang/Character.html#isDigit%28char%29) - Sean Patrick Floyd

22

使用Google Guava:

CharMatcher.inRange('0','9').retainFrom("123-456-789")

更新:

使用预计算的CharMatcher可以进一步提高性能。

CharMatcher ASCII_DIGITS=CharMatcher.inRange('0','9').precomputed();  
ASCII_DIGITS.retainFrom("123-456-789");

4
现在有预定义的 Charmatcher.DIGIT - Duncan McGregor

20
input.replaceAll("[^0-9?!\\.]","")

这将忽略小数点。

例如:如果您的输入为445.3kg,则输出将为445.3


我有一个叫做“4.5 zi.”的程序无法工作,因为它保留了第二个小数点。 - Marian Klühspies

11

使用Google Guava:

CharMatcher.DIGIT.retainFrom("123-456-789");

CharMatcher 是可插拔的并且非常有趣,例如您可以执行以下操作:

String input = "My phone number is 123-456-789!";
String output = CharMatcher.is('-').or(CharMatcher.DIGIT).retainFrom(input);

输出等于 123-456-789。


非常好的解决方案(+1),但它也遇到了其他人遇到的问题:许多字符被视为Unicode数字,而不仅仅是ASCII数字。此代码将保留所有这些字符:http://unicode.org/cldr/utility/list-unicodeset.jsp?a =%5Cp%7Bdigit%7D - Sean Patrick Floyd
@seanizer:那么这样会更好 CharMatcher.inRange('1','9').retainFrom("123-456-789") - Emil
@Emil 更像是CharMatcher.inRange('0','9'),但是:是的。 - Sean Patrick Floyd
inRange 是 CharMatcher.DIGIT 背后的实现;http://pastie.org/1252471。它只是考虑到了额外的 UTF 数字范围,我仍然认为这些数字是数字,因为实际上它们确实是,只是没有 ASCII 编码。 - BjornS
您还可以使用CharMatcher.JAVA_DIGIT来实现相同的目的,它只接受数字,就像Character.isDigit一样。 - BjornS

8
public class FindDigitFromString 
{

    public static void main(String[] args) 
    {
        String s="  Hi How Are You 11  ";        
        String s1=s.replaceAll("[^0-9]+", "");
        //*replacing all the value of string except digit by using "[^0-9]+" regex.*
       System.out.println(s1);          
   }
}

输出:11


7
使用正则表达式匹配您的需求。
String num,num1,num2;
String str = "123-456-789";
String regex ="(\\d+)";
Matcher matcher = Pattern.compile( regex ).matcher( str);
while (matcher.find( ))
{
num = matcher.group();     
System.out.print(num);                 
}

5

我受到了Sean Patrick Floyd的代码启发,并对其进行了小幅重写,以获得最大的性能。

public static String stripNonDigitsV2( CharSequence input ) {
    if (input == null)
        return null;
    if ( input.length() == 0 )
        return "";

    char[] result = new char[input.length()];
    int cursor = 0;
    CharBuffer buffer = CharBuffer.wrap( input );

    while ( buffer.hasRemaining() ) {
        char chr = buffer.get();
        if ( chr > 47 && chr < 58 )
            result[cursor++] = chr;
    }

    return new String( result, 0, cursor );
}

我对非常长的字符串进行了性能测试,结果如下:

  • 原始代码慢25.5%
  • Guava方法慢2.5-3倍
  • 使用D+的正则表达式慢3-3.5倍
  • 仅使用D的正则表达式慢25倍以上

不过这也取决于字符串的长度。当字符串只包含6个数字时,Guava慢50%,正则表达式慢1倍。


5
使用 Kotlin 和 Lambda 表达式,您可以这样做:
val digitStr = str.filter { it.isDigit() }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接