Извлечение цифр из строки в Java


207

У меня есть Stringобъект Java . Мне нужно извлечь только цифры из него. Я приведу пример:

"123-456-789" я хочу "123456789"

Есть ли библиотечная функция, которая извлекает только цифры?

Спасибо за ответы. Прежде чем я попробую это, мне нужно знать, нужно ли мне устанавливать какие-либо дополнительные библиотеки?

Ответы:


546

Вы можете использовать регулярные выражения и удалять не-цифры.

str = str.replaceAll("\\D+","");

6
хороший короткий код Линейный поиск может быть быстрее, но я думаю, что ваш имеет больше смысла.
Кастен

18
Я полагаю, что вы можете понизить голос, что угодно, чтобы понизить голос (без сарказма). Но мое личное мнение таково: когда великие разработчики (а у нас их много) бесплатно делятся некоторыми своими советами, тогда я буду соблюдать это, и я буду только понижать голос, что действительно ужасно (проверьте мой профиль, мой текущий соотношение составляет 14хх против 17 ниже). Но это моя личная философия, и ты свободен иметь свою собственную.
Шон Патрик Флойд

78
Это не будет работать, если ваш номер имеет десятичную точку, он также удаляет десятичную точку. str = str.replaceAll("[^\\.0123456789]","");
Аравиндан Р

2
Несмотря на то, что регулярное выражение в высшей степени простое и понятное, оно страдает от проблем с производительностью и должно использоваться только при наличии одноразовой полосы (например, при отправке формы). Если вы обрабатываете много данных, это не тот путь.
Брилл Паппин

2
и если вам нужно что-то исключить, например, десятичную точку,(?!\\.)
azerafati

49

Вот более подробное решение. Менее элегантно, но, вероятно, быстрее:

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()), чтобы он не нуждался в перераспределении. Вам не нужно требовать Stringздесь; CharSequenceдостаточно. Кроме того, вы можете отделить распределение объекта StringBuilderот набора нецифровых чисел, написав отдельную функцию, которая принимает в CharSequenceкачестве входных данных и Appendableэкземпляр в качестве накопителя выходных данных.
SEH

1
@seh Звучит интересно, но вместо того, чтобы комментировать, почему бы не создать свой собственный ответ с расширениями?
RedYeti

3
@RedYeti Позволить оставить этот ответ и добавить комментарий более благородно, так как тогда Шон получает отклики. Также намного быстрее критиковать чужой код, чем переписывать его, если вы спешите. Не наказывайте Сэ за внесение ценного вклада, ему не нужно было добавлять эти полезные лакомые кусочки, и ваш ответ снижает вероятность того, что он сделает это в следующий раз.
KomodoDave

2
Я никого не "наказываю" - это полное неверное истолкование того, что я говорил @seh. Моя точка зрения заключалась в том, что его комментарии добавили столько, что стоило, а на самом деле изменилось настолько, что я почувствовал, что это оправдывает собственный ответ. Я уверен, что Шон Патрик Флойд не заинтересован в том, чтобы слава только помогать другим, и был бы очень рад, если бы он предоставил свой собственный ответ. Я просто воодушевлял Сэ, так как чувствовал, что его вклад заслуживает большей наглядности. Как можно прочитать мой комментарий, как что-нибудь еще, полностью озадачивает меня, но я прошу прощения за seh, если это каким-то образом.
RedYeti

1
Мне нравится, как эти дискуссии возобновляются после того, как они некоторое время бездействуют. Пожалуй, лучшее, что можно сделать здесь, - это отредактировать ответ Шона, дополнив его своими предложениями. Таким образом, Шон продолжит получать кредит, если ответ не перейдет в статус вики сообщества.
Се

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 (см. Документы: download.oracle.com/javase/6/docs/api/java/lang/… )
Шон Патрик Флойд

21

Использование Google Guava:

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

ОБНОВИТЬ:

Использование Precomputed CharMatcher может еще больше улучшить производительность

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

3
Там сейчас Charmatcher.DIGITпредопределено.
Дункан МакГрегор

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

Это будет игнорировать десятичные точки.

Например: если у вас есть вход в 445.3kgкачестве выхода будет 445.3.


У меня "4,5 зи". не работает, потому что держит второе. тоже
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), но оно страдает от той же проблемы, что и другие: многие символы квалифицируются как цифры Юникода, а не только цифры ascii. Этот код сохранит все эти символы: unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bdigit%7D
Шон Патрик Флойд,

@seanizer: Тогда это будет лучше CharMatcher.inRange ('1', '9'). retainFrom ("123-456-789")
Эмиль

@ Эмиль больше похож на CharMatcher.inRange ('0', '9'), но: да
Шон Патрик Флойд

inRange - это то, что стоит за CharMatcher.DIGIT; pastie.org/1252471 Он просто учитывает диапазоны значений UTF, но я бы все равно считал их цифрами, поскольку в действительности они просто не кодируются в ASCII.
BjornS

Вы также можете использовать CharMatcher.JAVA_DIGIT для той же цели, которая будет принимать только цифры в соответствии с Character.isDigit
BjornS

6

Используйте регулярное выражение, чтобы соответствовать вашему требованию.

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

Я вдохновлен кодом Шона Патрика Флойда и немного переписал его для максимальной производительности, которую я получаю.

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%
  • Подход гуавы медленнее в 2,5-3 раза
  • Регулярное выражение с D + в 3-3,5 раза медленнее
  • Регулярное выражение только с D в 25+ раз медленнее

Кстати, это зависит от того, как долго эта строка. Со строкой, содержащей только 6 чисел, гуава на 50% медленнее и регулярное выражение в 1 раз медленнее


5
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



2

Я доработал код для телефонных номеров +9 (987) 124124.

Символы Юникода занимают 4 байта.

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 );
    int i=0;
    while ( i< buffer.length()  ) { //buffer.hasRemaining()
        char chr = buffer.get(i);
        if (chr=='u'){
            i=i+5;
            chr=buffer.get(i);
        }

        if ( chr > 39 && chr < 58 )
            result[cursor++] = chr;
        i=i+1;
    }

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


0
import java.util.*;
public class FindDigits{

 public static void main(String []args){
    FindDigits h=new  FindDigits();
    h.checkStringIsNumerical();
 }

 void checkStringIsNumerical(){
    String h="hello 123 for the rest of the 98475wt355";
     for(int i=0;i<h.length();i++)  {
      if(h.charAt(i)!=' '){
       System.out.println("Is this '"+h.charAt(i)+"' is a digit?:"+Character.isDigit(h.charAt(i)));
       }
    }
 }

void checkStringIsNumerical2(){
    String h="hello 123 for 2the rest of the 98475wt355";
     for(int i=0;i<h.length();i++)  {
         char chr=h.charAt(i);
      if(chr!=' '){
       if(Character.isDigit(chr)){
          System.out.print(chr) ;
       }
       }
    }
 }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.