Extrair dígitos de uma sequência em Java

207

Eu tenho um Stringobjeto Java . Eu preciso extrair apenas dígitos dele. Vou dar um exemplo:

"123-456-789" eu quero "123456789"

Existe uma função de biblioteca que extrai apenas dígitos?

Obrigado pelas respostas. Antes de experimentar, preciso saber se tenho que instalar alguma biblioteca adicional?

user488469
fonte

Respostas:

546

Você pode usar regex e excluir não dígitos.

str = str.replaceAll("\\D+","");
codaddict
fonte
6
bom código curto. Uma pesquisa linear pode ser mais rápida, mas acho que a sua faz mais sentido.
Kasten
18
Eu acho que você pode diminuir o voto de qualquer coisa que você gostaria de votar (sem intenção de sarcasmo). Mas minha opinião pessoal é: quando grandes desenvolvedores (e temos muitos deles aqui) compartilharem alguns de seus conselhos de graça, então eu irei honrá-lo, e eu apenas desisto de coisas realmente terríveis (veja meu perfil, meu perfil atual). a relação é 14xx acima contra 17 abaixo). Mas essa é a minha filosofia pessoal e você é livre para ter a sua.
Sean Patrick Floyd
78
Isso não funcionará se o seu número tiver um ponto decimal, ele também removerá o ponto decimal. str = str.replaceAll("[^\\.0123456789]","");
Aravindan R
2
Embora o regex seja extremamente simples e limpo de analisar, ele sofre de problemas de desempenho e só deve ser usado onde você tem uma faixa única (como um envio de formulário). Se você estiver processando muitos dados, esse não é o caminho a seguir.
Brill Pappin
2
e se você precisar excluir qualquer coisa, como um ponto decimal,(?!\\.)
azerafati
49

Aqui está uma solução mais detalhada. Menos elegante, mas provavelmente mais rápido:

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

Código do teste:

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

Resultado:

0123456789

BTW: Eu não usei Character.isDigit (ch) porque ele aceita muitos outros caracteres, exceto 0 - 9.

Sean Patrick Floyd
fonte
4
Você deve fornecer um tamanho ao StringBuilderconstrutor (como input.length()) para garantir que ele não precise ser realocado. Você não precisa exigir um Stringaqui; CharSequenceé suficiente. Além disso, você pode separar a alocação do StringBuilderda coleção de não dígitos, escrevendo uma função separada que aceite a CharSequencecomo entrada e uma Appendableinstância como um acumulador de saída.
seh
1
@seh Parece interessante, mas em vez de comentar, por que não criar sua própria resposta com as extensões?
RedYeti
3
@RedYeti Deixar esta resposta permanecer e adicionar um comentário é mais honroso, já que Sean recebe votos positivos. Também é muito mais rápido criticar o código de outras pessoas do que reescrevê-lo se você estiver com pressa. Não castigue seh por dar uma contribuição valiosa, ele não precisou adicionar esses boatos úteis, e sua resposta o torna menos provável de fazê-lo na próxima vez.
KomodoDave
2
Não estou "punindo" ninguém - isso é uma completa interpretação incorreta do que eu estava dizendo para @seh. O que quero dizer é que os comentários dele acrescentaram tanto que valia a pena e, de fato, mudaram tanto que achei que isso merecia uma resposta própria. Tenho certeza de que Sean Patrick Floyd não está preocupado com o parabéns, apenas ajudando os outros e ficaria perfeitamente feliz em fornecer sua própria resposta. Eu estava apenas encorajando seh, pois senti que sua contribuição merecia maior visibilidade. Como é possível ler meu comentário como qualquer outra coisa completamente me intriga, mas peço desculpas seh de alguma forma.
RedYeti
1
Eu gosto de como essas discussões são retomadas depois de ficarem inativas por um tempo. Talvez a melhor coisa a fazer aqui seja editar a resposta de Sean, aumentando-a com minhas sugestões. Dessa forma, Sean continuará recebendo o crédito, a menos que a resposta seja transferida para o status do wiki da comunidade.
SEH
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();
}
dogbane
fonte
Pensei em usar o Character.isDigit (), mas ele também aceita alguns caracteres que não são de 0 a 9 (consulte a documentação: download.oracle.com/javase/6/docs/api/java/lang/… )
Sean Patrick Floyd
21

Usando o Google Guava:

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

ATUALIZAR:

O uso do CharMatcher pré-computado pode melhorar ainda mais o desempenho

CharMatcher ASCII_DIGITS=CharMatcher.inRange('0','9').precomputed();  
ASCII_DIGITS.retainFrom("123-456-789");
Emil
fonte
3
Agora está Charmatcher.DIGITpredefinido.
Duncan McGregor
15
input.replaceAll("[^0-9?!\\.]","")

Isso ignorará os pontos decimais.

por exemplo: se você tiver uma entrada como 445.3kgserá a saída 445.3.

user3679646
fonte
Eu tenho "4.5 zi". não está funcionando porque mantém o segundo. também
Marian Klühspies
11

Usando o Google Guava:

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

O CharMatcher é plugável e bastante interessante de usar, por exemplo, você pode fazer o seguinte:

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

saída == 123-456-789

BjornS
fonte
Solução muito boa (+1), mas sofre do mesmo problema que os outros: muitos caracteres se qualificam como dígitos unicode, não apenas os dígitos ascii. Este código manterá todos esses caracteres: unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bdigit%7D
Sean Patrick Floyd
@seanizer: Então será melhor CharMatcher.inRange ('1', '9'). reterFrom ("123-456-789")
Emil
@Emil mais como CharMatcher.inRange ('0', '9'), mas: sim
Sean Patrick Floyd
inRange é o que está por trás do CharMatcher.DIGIT; pastie.org/1252471 Simplesmente leva em consideração os intervalos de números UTF, eu ainda os consideraria como dígitos, pois na realidade eles são, eles simplesmente não são codificados em ASCII.
Bjorns
Você também pode usar CharMatcher.JAVA_DIGIT para a mesma finalidade, que aceitará apenas dígitos conforme Character.isDigit
BjornS
6

Use expressão regular para corresponder aos seus requisitos.

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);                 
}
Raghunandan
fonte
5

Inspirei-me no código Sean Patrick Floyd e pouco o reescrevi para obter o máximo desempenho que recebo.

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

Eu faço o teste de desempenho para uma string muito longa com números mínimos e o resultado é:

  • O código original é 25,5% mais lento
  • A abordagem da goiaba é 2,5-3 vezes mais lenta
  • A expressão regular com D + é 3-3,5 vezes mais lenta
  • Expressão regular com apenas D é 25 vezes mais lenta

Btw depende de quanto tempo essa cadeia é. Com uma string que contém apenas 6 números, a goiaba é 50% mais lenta e a regexp 1 vezes mais lenta

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

Saída: 11

ruchin khare
fonte
3

Você pode usar str.replaceAll("[^0-9]", "");

sendon1982
fonte
2

Finalizei o código para os números de telefone +9 (987) 124124.

Caracteres Unicode ocupam 4 bytes.

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 );
}
Kairat Koibagarov
fonte
2

Código:

public class saasa {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String t="123-456-789";
        t=t.replaceAll("-", "");
        System.out.println(t);
    }
nagalakshmi kotha
fonte
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) ;
       }
       }
    }
 }
}
sarkar vijay
fonte