Como extrair números de uma string e obter uma matriz de ints?

109

Eu tenho uma variável String (basicamente uma frase em inglês com um número não especificado de números) e gostaria de extrair todos os números em uma matriz de inteiros. Eu queria saber se existe uma solução rápida com expressões regulares?


Usei a solução de Sean e mudei um pouco:

LinkedList<String> numbers = new LinkedList<String>();

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(line); 
while (m.find()) {
   numbers.add(m.group());
}
John Manak
fonte
1
Os números estão entre espaços ou outros caracteres? Como os números são formatados, eles são hexadecimais, octais, binários, decimais?
Buhake Sindi
Achei que estava claro pela pergunta: é uma frase em inglês com números. Além disso, eu estava falando sobre um array de inteiros, então o que eu estava procurando eram inteiros.
John Manak,

Respostas:

175
Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There are more than -2 and less than 12 numbers here");
while (m.find()) {
  System.out.println(m.group());
}

... imprime -2e 12.


-? corresponde a um sinal negativo inicial - opcionalmente. \ d corresponde a um dígito, e precisamos escrever \como \\em uma string Java. Portanto, \ d + corresponde a 1 ou mais dígitos.

Sean Owen
fonte
4
Você poderia complementar sua resposta explicando sua expressão regular, por favor?
OscarRyz
3
-? corresponde a um sinal negativo inicial - opcionalmente. \ d corresponde a um dígito, e precisamos escrever \ as \\ em uma string Java. Portanto, \\ d + corresponde a mais 1 dígito
Sean Owen,
7
Mudei minha expressão para Pattern.compile ("-? [\\ d \\.] +") Para oferecer suporte a flutuadores. Você definitivamente me guia no caminho, Thx!
jlengrand
Este método detecta dígitos, mas não detecta números formatados, por exemplo 2,000. Para tal uso-?\\d+,?\\d+|-?\\d+
Mugoma J. Okomba
Isso suporta apenas uma única vírgula, portanto, perderia "2.000.000". Ele também aceita strings como "2,00". Se separadores de vírgula devem ser suportados, então: -?\\d+(,\\d{3})*deve funcionar.
Sean Owen,
52

Que tal usar o replaceAllmétodo java.lang.String:

    String str = "qwerty-1qwerty-2 455 f0gfg 4";      
    str = str.replaceAll("[^-?0-9]+", " "); 
    System.out.println(Arrays.asList(str.trim().split(" ")));

Resultado:

[-1, -2, 455, 0, 4]

Descrição

[^-?0-9]+
  • [e ]delimita um conjunto de caracteres para uma única correspondência, ou seja, apenas uma vez em qualquer ordem
  • ^Identificador especial usado no início do conjunto, usado para indicar a correspondência de todos os caracteres não presentes no conjunto delimitado, em vez de todos os caracteres presentes no conjunto.
  • + Entre uma e ilimitadas vezes, tantas vezes quanto possível, retribuindo conforme necessário
  • -? Um dos personagens “-” e “?”
  • 0-9 Um caractere no intervalo entre “0” e “9”
Maxim Shoustin
fonte
4
Por que você deseja manter pontos de interrogação? Além disso, este trata -por si só como um número, juntamente com coisas como 9-, ---6, e 1-2-3.
Alan Moore
1
Uma alternativa muito boa sem usar bibliotecas de importação;)
Jcc.Sanabria
18
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(myString);
while (m.find()) {
    int n = Integer.parseInt(m.group());
    // append n to list
}
// convert list to array, etc

Na verdade, você pode substituir [0-9] por \ d, mas isso envolve um escape de barra invertida dupla, o que torna a leitura mais difícil.

sideral
fonte
Opa. Sean lida com números negativos, o que é uma melhoria.
sideral
2
o seu
lidará
9
  StringBuffer sBuffer = new StringBuffer();
  Pattern p = Pattern.compile("[0-9]+.[0-9]*|[0-9]*.[0-9]+|[0-9]+");
  Matcher m = p.matcher(str);
  while (m.find()) {
    sBuffer.append(m.group());
  }
  return sBuffer.toString();

Isso é para extrair números retendo o decimal

Kannan
fonte
Não lida com negativos
OneCricketeer
5

A resposta aceita detecta dígitos, mas não detecta números formatados, por exemplo, 2.000, nem decimais, por exemplo, 4,8. Para tal uso -?\\d+(,\\d+)*?\\.?\\d+?:

        Pattern p = Pattern.compile("-?\\d+(,\\d+)*?\\.?\\d+?");
        List<String> numbers = new ArrayList<String>();
        Matcher m = p.matcher("Government has distributed 4.8 million textbooks to 2,000 schools");
        while (m.find()) {  
            numbers.add(m.group());
        }   
        System.out.println(numbers);

Resultado: [4.8, 2,000]

Mugoma J. Okomba
fonte
1
@JulienS .: Eu discordo. Esta regex faz muito mais do que o OP pediu, e de maneira incorreta. (No mínimo, a parte decimal deve estar em um grupo opcional, com tudo nele obrigatório e ganancioso:. (?:\.\d+)?)
Alan Moore
Você certamente tem um ponto aí para a parte decimal. No entanto, é muito comum encontrar números formatados.
Julien de
@AlanMoore muitos visitantes do SO estão procurando maneiras diferentes de resolver problemas com semelhanças / diferenças variadas, e é útil que sejam apresentadas sugestões. Até mesmo o OP pode ter simplificado demais.
Mugoma J. Okomba
4

para números racionais, use este: (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))

Andrey
fonte
1
O OP disse números inteiros, não números reais. Além disso, você se esqueceu de escapar dos pontos e nenhum desses parênteses é necessário.
Alan Moore,
3

Usando o Java 8, você pode fazer:

String str = "There 0 are 1 some -2-34 -numbers 567 here 890 .";
int[] ints = Arrays.stream(str.replaceAll("-", " -").split("[^-\\d]+"))
                 .filter(s -> !s.matches("-?"))
                 .mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

Se você não tiver números negativos, pode se livrar do replaceAll(e usar !s.isEmpty()em filter), pois isso é apenas para dividir corretamente algo como 2-34(isso também pode ser tratado puramente com regex em split, mas é bastante complicado).

Arrays.streamtransforma nosso String[]em um Stream<String>.

filter livra-se das strings vazias iniciais e finais, bem como de qualquer - que não faça parte de um número.

mapToInt(Integer::parseInt).toArray()pede parseInta cada um Stringpara nos dar um int[].


Como alternativa, o Java 9 tem um método Matcher.results , que deve permitir algo como:

Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There 0 are 1 some -2-34 -numbers 567 here 890 .");
int[] ints = m.results().map(MatchResults::group).mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

Do jeito que está, nada disso é uma grande melhoria em relação a apenas repetir os resultados com Pattern/ Matcherconforme mostrado nas outras respostas, mas deve ser mais simples se você quiser seguir com operações mais complexas que são significativamente simplificadas com o uso de córregos.

Bernhard Barker
fonte
1

Extraia todos os números reais usando isso.

public static ArrayList<Double> extractNumbersInOrder(String str){

    str+='a';
    double[] returnArray = new double[]{};

    ArrayList<Double> list = new ArrayList<Double>();
    String singleNum="";
    Boolean numStarted;
    for(char c:str.toCharArray()){

        if(isNumber(c)){
            singleNum+=c;

        } else {
            if(!singleNum.equals("")){  //number ended
                list.add(Double.valueOf(singleNum));
                System.out.println(singleNum);
                singleNum="";
            }
        }
    }

    return list;
}


public static boolean isNumber(char c){
    if(Character.isDigit(c)||c=='-'||c=='+'||c=='.'){
        return true;
    } else {
        return false;
    }
}
Swagger 68
fonte
1

Caracteres de fração e agrupamento para representar números reais podem diferir entre os idiomas. O mesmo número real pode ser escrito de maneiras muito diferentes, dependendo do idioma.

O número dois milhões em alemão

2.000.000,00

e em ingles

2.000.000,00

Um método para extrair totalmente números reais de uma determinada string de uma forma agnóstica de linguagem:

public List<BigDecimal> extractDecimals(final String s, final char fraction, final char grouping) {
    List<BigDecimal> decimals = new ArrayList<BigDecimal>();
    //Remove grouping character for easier regexp extraction
    StringBuilder noGrouping = new StringBuilder();
    int i = 0;
    while(i >= 0 && i < s.length()) {
        char c = s.charAt(i);
        if(c == grouping) {
            int prev = i-1, next = i+1;
            boolean isValidGroupingChar =
                    prev >= 0 && Character.isDigit(s.charAt(prev)) &&
                    next < s.length() && Character.isDigit(s.charAt(next));                 
            if(!isValidGroupingChar)
                noGrouping.append(c);
            i++;
        } else {
            noGrouping.append(c);
            i++;
        }
    }
    //the '.' character has to be escaped in regular expressions
    String fractionRegex = fraction == POINT ? "\\." : String.valueOf(fraction);
    Pattern p = Pattern.compile("-?(\\d+" + fractionRegex + "\\d+|\\d+)");
    Matcher m = p.matcher(noGrouping);
    while (m.find()) {
        String match = m.group().replace(COMMA, POINT);
        decimals.add(new BigDecimal(match));
    }
    return decimals;
}
E nós
fonte
1

Se você deseja excluir os números contidos nas palavras, como bar1 ou aa1bb, adicione limites de palavras \ b a qualquer uma das respostas baseadas em regex. Por exemplo:

Pattern p = Pattern.compile("\\b-?\\d+\\b");
Matcher m = p.matcher("9There 9are more9 th9an -2 and less than 12 numbers here9");
while (m.find()) {
  System.out.println(m.group());
}

exibe:

2
12
dxl
fonte
1

Eu sugeriria verificar os valores ASCII para extrair números de uma String Suponha que você tenha uma String de entrada como meunome12345 e se você quiser apenas extrair os números 12345, você pode fazer isso primeiro convertendo a String em Matriz de Caracteres e então use o seguinte pseudocódigo

    for(int i=0; i < CharacterArray.length; i++)
    {
        if( a[i] >=48 && a[i] <= 58)
            System.out.print(a[i]);
    }

uma vez que os números são extraídos, anexe-os a um array

Espero que isto ajude

The_Fresher
fonte
Uma string Java é uma sequência contada de unidades de código Unicode / UTF-16. Pelo design do UTF-16, os primeiros 128 caracteres têm o mesmo valor (mas não têm o mesmo tamanho) que sua codificação ASCII; Além disso, pensar que está lidando com ASCII levará a erros.
Tom Blodget
0

Eu achei esta expressão mais simples

String[] extractednums = msg.split("\\\\D++");
user2902302
fonte
-1
public static String extractNumberFromString(String number) {
    String num = number.replaceAll("[^0-9]+", " ");
    return num.replaceAll(" ", "");
}

extrai apenas números da string

user3509903
fonte