¿Cómo extraer números de una cadena y obtener una matriz de entradas?

109

Tengo una variable de cadena (básicamente una oración en inglés con un número de números no especificado) y me gustaría extraer todos los números en una matriz de números enteros. Me preguntaba si había una solución rápida con expresiones regulares.


Usé la solución de Sean y la cambié ligeramente:

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
fuente
1
¿Los números están rodeados de espacios u otros caracteres? ¿Cómo se formatean los números? ¿Son hexadecimales, octales, binarios, decimales?
Buhake Sindi
Pensé que estaba claro por la pregunta: es una oración en inglés con números. Además, estaba hablando de una matriz de enteros, así que lo que estaba buscando eran enteros.
John Manak

Respuestas:

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

... impresiones -2 y 12.


-? coincide con un signo negativo inicial, opcionalmente. \ d coincide con un dígito, y debemos escribir \como \\en una cadena Java. Entonces, \ d + coincide con 1 o más dígitos.

Sean Owen
fuente
4
¿Podría complementar su respuesta explicando su expresión regular, por favor?
OscarRyz
3
-? coincide con un signo negativo inicial, opcionalmente. \ d coincide con un dígito, y necesitamos escribir \ as \\ en una cadena Java. Entonces, \\ d + coincide con 1 dígito más
Sean Owen
7
Cambié mi expresión a Pattern.compile ("-? [\\ d \\.] +") Para admitir flotadores. ¡Definitivamente me guiaste en el camino, Thx!
jlengrand
Este método detecta dígitos pero no detecta números formateados, p 2,000. Ej . Para tal uso-?\\d+,?\\d+|-?\\d+
Mugoma J. Okomba
Eso solo admite una sola coma, por lo que faltaría "2,000,000". También acepta cadenas como "2,00". Si se deben admitir separadores de coma, entonces: -?\\d+(,\\d{3})*debería funcionar.
Sean Owen
52

¿Qué pasa con el 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(" ")));

Salida:

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

Descripción

[^-?0-9]+
  • [y ]delimita un conjunto de caracteres para que coincidan individualmente, es decir, solo una vez en cualquier orden
  • ^Identificador especial utilizado al principio del conjunto, utilizado para indicar que coinciden todos los caracteres que no están presentes en el conjunto delimitado, en lugar de todos los caracteres presentes en el conjunto.
  • + Entre una y una cantidad ilimitada de veces, tantas veces como sea posible, devolviendo según sea necesario
  • -? Uno de los caracteres "-" y "?"
  • 0-9 Un carácter en el rango entre "0" y "9"
Maxim Shoustin
fuente
4
¿Por qué querrías tener signos de interrogación? Además, este trata -por sí mismo como un número, junto con cosas como 9-, ---6, y 1-2-3.
Alan Moore
1
Una muy buena alternativa sin importar bibliotecas;)
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

En realidad, puede reemplazar [0-9] con \ d, pero eso implica un escape de doble barra invertida, lo que hace que sea más difícil de leer.

sideral
fuente
¡Ups! Sean's maneja números negativos, eso es una mejora.
sideral
2
el suyo también manejará números negativos si usa "-? [0-9] +"
cegprakash
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();

Esto es para extraer números reteniendo el decimal

Kannan
fuente
No maneja negativos
OneCricketeer
5

La respuesta aceptada detecta dígitos pero no detecta números formateados, por ejemplo, 2000, ni decimales, por ejemplo, 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);

Salida: [4.8, 2,000]

Mugoma J. Okomba
fuente
1
@JulienS .: No estoy de acuerdo. Esta expresión regular hace mucho más de lo que pidió el OP, y lo hace incorrectamente. (Al menos, la parte decimal debe estar en un grupo opcional, con todo lo requerido y codicioso:. (?:\.\d+)?)
Alan Moore
Ciertamente tiene un punto para la parte decimal. Sin embargo, es muy común encontrar números formateados.
Julien
@AlanMoore muchos visitantes de SO están buscando formas diferentes de resolver problemas con diferentes similitudes / diferencias, y es útil que surjan sugerencias. Incluso el OP podría haberse simplificado demasiado.
Mugoma J. Okomba
4

para números racionales usa este: (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))

Andrey
fuente
1
El OP decía enteros, no números reales. Además, olvidó escapar de los puntos y ninguno de esos paréntesis es necesario.
Alan Moore
3

Con Java 8, puede hacer:

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]

Si no tiene números negativos, puede deshacerse de replaceAll(y usar !s.isEmpty()en filter), ya que eso es solo para dividir correctamente algo como 2-34(esto también se puede manejar puramente con expresiones regulares split, pero es bastante complicado).

Arrays.streamconvierte nuestro String[]en un Stream<String>.

filterelimina las cadenas vacías iniciales y finales, así como las -que no forman parte de un número.

mapToInt(Integer::parseInt).toArray()pide parseInta cada uno Stringque nos dé un int[].


Alternativamente, Java 9 tiene un método Matcher.results , que debería 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]

Tal como está, ninguno de estos es una gran mejora con respecto a simplemente recorrer los resultados con Pattern/ Matchercomo se muestra en las otras respuestas, pero debería ser más simple si desea seguir esto con operaciones más complejas que se simplifican significativamente con el uso de arroyos.

Bernhard Barker
fuente
1

Extrae todos los números reales usando esto.

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
fuente
1

Los caracteres de fracciones y agrupaciones para representar números reales pueden diferir entre idiomas. El mismo número real podría escribirse de formas muy diferentes según el idioma.

El número dos millones en alemán

2,000,000.00

y en ingles

2.000.000,00

Un método para extraer completamente números reales de una cadena dada de una manera independiente del idioma:

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;
}
Y nosotros
fuente
1

Si desea excluir los números que están contenidos en palabras, como bar1 o aa1bb, agregue límites de palabras \ b a cualquiera de las respuestas basadas en expresiones regulares. Por ejemplo:

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

muestra:

2
12
dxl
fuente
1

Sugeriría verificar los valores ASCII para extraer números de una cadena. Supongamos que tiene una cadena de entrada como myname12345 y si solo desea extraer los números 12345 , puede hacerlo convirtiendo primero la cadena en una matriz de caracteres y luego use el siguiente pseudocódigo

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

Una vez extraídos los números, añádalos a una matriz.

Espero que esto ayude

The_Fresher
fuente
Una cadena Java es una secuencia contada de unidades de código Unicode / UTF-16. Según el diseño de UTF-16, los primeros 128 caracteres tienen el mismo valor (pero no el mismo tamaño) que su codificación ASCII; Más allá de eso, pensar que se trata de ASCII conducirá a errores.
Tom Blodget
0

Encontré esta expresión más simple

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

extrae solo números de la cadena

usuario3509903
fuente