Uso de expresiones regulares para extraer un valor en Java


169

Tengo varias cadenas en forma aproximada:

[some text] [some number] [some more text]

Quiero extraer el texto en [algún número] usando las clases Java Regex.

Sé aproximadamente qué expresión regular quiero usar (aunque todas las sugerencias son bienvenidas). Lo que realmente me interesa son las llamadas de Java para tomar la cadena de expresiones regulares y usarla en los datos de origen para producir el valor de [algún número].

EDITAR: debo agregar que solo estoy interesado en un solo [algún número] (básicamente, la primera instancia). Las cadenas de origen son cortas y no voy a buscar múltiples ocurrencias de [algún número].


11
... y ahora me voy a investigar. Veamos si SO puede obtener una respuesta para mí antes de resolverlo yo mismo. :-P
Craig Walker

Esta fue una pregunta de entrevista en una empresa de banca / inversión / comercio para ingeniería de software, ¿no? : P
ennth

@ennth ¡No, ni siquiera cerca! Fue para el código de producción en un sitio web de negocios pequeños ... hace muchas lunas.
Craig Walker

1
maldita sea, me hicieron casi la misma pregunta exacta en un examen de codificación de JP Morgan Chase Software Engineering hace solo unos días: P
es

Respuestas:


316

Ejemplo completo:

private static final Pattern p = Pattern.compile("^([a-zA-Z]+)([0-9]+)(.*)");
public static void main(String[] args) {
    // create matcher for pattern p and given string
    Matcher m = p.matcher("Testing123Testing");

    // if an occurrence if a pattern was found in a given string...
    if (m.find()) {
        // ...then you can use group() methods.
        System.out.println(m.group(0)); // whole matched expression
        System.out.println(m.group(1)); // first expression from round brackets (Testing)
        System.out.println(m.group(2)); // second one (123)
        System.out.println(m.group(3)); // third one (Testing)
    }
}

Como está buscando el primer número, puede usar dicha expresión regular:

^\D+(\d+).*

y m.group(1)te devolveré el primer número. Tenga en cuenta que los números con signo pueden contener un signo menos:

^\D+(-?\d+).*

62
No olvides reutilizar el objeto Patter. La compilación de patrones toma una gran cantidad de tiempo.
Rastislav Komara

14
Convenido. Por lo general, definiría el patrón como un patrón estático privado final PATTERN = Pattern.compile ("..."); Pero solo soy yo.
Allain Lalonde

66
simplemente podemos usar Pattern p = Pattern.compile ("\\ d +");
javaMan

15
Sin explicación, esta es una respuesta pobre.
Martin Spamer

También puede reutilizar el Matcher. Llame al método reset () de Matcher entre cada uso. Si está compartiendo el emparejador a través de múltiples hilos concurrentes, debe sincronizar la operación.
Márquez

41
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Regex1 {
    public static void main(String[]args) {
        Pattern p = Pattern.compile("\\d+");
        Matcher m = p.matcher("hello1234goodboy789very2345");
        while(m.find()) {
            System.out.println(m.group());
        }
    }
}

Salida:

1234
789
2345

La pregunta específicamente pide solo la PRIMERA aparición de números.
NoBrainer

34

Allain básicamente tiene el código de Java, por lo que puede usarlo. Sin embargo, su expresión solo coincide si sus números solo están precedidos por una secuencia de caracteres de palabras.

"(\\d+)"

debería poder encontrar la primera cadena de dígitos. No necesita especificar qué hay antes, si está seguro de que será la primera cadena de dígitos. Del mismo modo, no sirve de nada especificar qué hay después, a menos que lo desee. Si solo desea el número y está seguro de que será la primera cadena de uno o más dígitos, entonces eso es todo lo que necesita.

Si espera que esté compensado por espacios, hará que sea aún más claro especificar

"\\s+(\\d+)\\s+"

podría ser mejor.

Si necesita las tres partes, esto hará:

"(\\D+)(\\d+)(.*)"

EDITAR Las expresiones dadas por Allain y Jack sugieren que debe especificar algún subconjunto de no dígitos para capturar dígitos . Si le dice al motor de expresiones regulares que está buscando \d, ignorará todo antes de los dígitos. Si la expresión de J o A se ajusta a su patrón, toda la coincidencia es igual a la cadena de entrada . Y no hay razón para especificarlo. Probablemente ralentiza un partido limpio, si no se ignora por completo.


Puede probar la hipótesis de Axemans ejecutando una prueba de muestra y comprobando el rendimiento de su solución vs. A / J.
anjanb

No necesita especificar el principio y el final de la cadena. De lo contrario, cosas como 124xxx123xxx coincidirían aunque no encajen en su sintaxis. ¿O son ^ y $ implícitos?
Allain Lalonde

Allain, el tuyo también fallaría. Usted y Jack suponen que los caracteres que no son dígitos precederán a los dígitos. O lo hacen o no lo hacen. En cuyo caso, ninguna de estas expresiones analizará esta línea. Repito que como se especifica , el patrón para los dígitos es suficiente.
Axeman

11

Además de Pattern , la clase Java String también tiene varios métodos que pueden funcionar con expresiones regulares, en su caso el código será:

"ab123abc".replaceFirst("\\D*(\\d*).*", "$1")

donde \\Des un carácter sin dígitos.


10

En Java 1.4 y superior:

String input = "...";
Matcher matcher = Pattern.compile("[^0-9]+([0-9]+)[^0-9]+").matcher(input);
if (matcher.find()) {
    String someNumberStr = matcher.group(1);
    // if you need this to be an int:
    int someNumberInt = Integer.parseInt(someNumberStr);
}

8

Esta función recopila todas las secuencias coincidentes de la cadena. En este ejemplo, toma todas las direcciones de correo electrónico de la cadena.

static final String EMAIL_PATTERN = "[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
        + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})";

public List<String> getAllEmails(String message) {      
    List<String> result = null;
    Matcher matcher = Pattern.compile(EMAIL_PATTERN).matcher(message);

    if (matcher.find()) {
        result = new ArrayList<String>();
        result.add(matcher.group());

        while (matcher.find()) {
            result.add(matcher.group());
        }
    }

    return result;
}

Para message = "adf@gmail.com, <another@osiem.osiem>>>> lalala@aaa.pl"ello creará la Lista de 3 elementos.


3

Intenta hacer algo como esto:

Pattern p = Pattern.compile("^.+(\\d+).+");
Matcher m = p.matcher("Testing123Testing");

if (m.find()) {
    System.out.println(m.group(1));
}

3
-1. Debido a que .+codiciosamente consume caracteres, \d+solo captura los "3"de "123". Además, dentro de los literales de cadena, debe escapar de la barra diagonal inversa (su ejemplo no se compilará).
Bart Kiers

3

Solución simple

// Regexplanation:
// ^       beginning of line
// \\D+    1+ non-digit characters
// (\\d+)  1+ digit characters in a capture group
// .*      0+ any character
String regexStr = "^\\D+(\\d+).*";

// Compile the regex String into a Pattern
Pattern p = Pattern.compile(regexStr);

// Create a matcher with the input String
Matcher m = p.matcher(inputStr);

// If we find a match
if (m.find()) {
    // Get the String from the first capture group
    String someDigits = m.group(1);
    // ...do something with someDigits
}

Solución en una clase de utilidad

public class MyUtil {
    private static Pattern pattern = Pattern.compile("^\\D+(\\d+).*");
    private static Matcher matcher = pattern.matcher("");

    // Assumptions: inputStr is a non-null String
    public static String extractFirstNumber(String inputStr){
        // Reset the matcher with a new input String
        matcher.reset(inputStr);

        // Check if there's a match
        if(matcher.find()){
            // Return the number (in the first capture group)
            return matcher.group(1);
        }else{
            // Return some default value, if there is no match
            return null;
        }
    }
}

...

// Use the util function and print out the result
String firstNum = MyUtil.extractFirstNumber("Testing4234Things");
System.out.println(firstNum);

1

Mira, puedes hacerlo usando StringTokenizer

String str = "as:"+123+"as:"+234+"as:"+345;
StringTokenizer st = new StringTokenizer(str,"as:");

while(st.hasMoreTokens())
{
  String k = st.nextToken();    // you will get first numeric data i.e 123
  int kk = Integer.parseInt(k);
  System.out.println("k string token in integer        " + kk);

  String k1 = st.nextToken();   //  you will get second numeric data i.e 234
  int kk1 = Integer.parseInt(k1);
  System.out.println("new string k1 token in integer   :" + kk1);

  String k2 = st.nextToken();   //  you will get third numeric data i.e 345
  int kk2 = Integer.parseInt(k2);
  System.out.println("k2 string token is in integer   : " + kk2);
}

Dado que estamos tomando estos datos numéricos en tres variables diferentes, podemos usar estos datos en cualquier parte del código (para su uso posterior)


0

¿Qué tal [^\\d]*([0-9]+[\\s]*[.,]{0,1}[\\s]*[0-9]*).*si creo que se encargaría de los números con parte fraccionaria? Incluí espacios en blanco e incluí ,como posible separador. Estoy tratando de obtener los números de una cadena que incluye flotantes y teniendo en cuenta que el usuario puede cometer un error e incluir espacios en blanco al escribir el número.


0

A veces puede usar el método simple .split ("REGEXP") disponible en java.lang.String. Por ejemplo:

String input = "first,second,third";

//To retrieve 'first' 
input.split(",")[0] 
//second
input.split(",")[1]
//third
input.split(",")[2]

0
Pattern p = Pattern.compile("(\\D+)(\\d+)(.*)");
Matcher m = p.matcher("this is your number:1234 thank you");
if (m.find()) {
    String someNumberStr = m.group(2);
    int someNumberInt = Integer.parseInt(someNumberStr);
}

1
Edite con más información. Se desaconsejan las respuestas de solo código y "pruebe esto", ya que no contienen contenido que se pueda buscar y no explican por qué alguien debería "probar esto". Hacemos un esfuerzo aquí para ser un recurso para el conocimiento.
Brian Tompsett - 汤 莱恩

1
Voto negativo por solo repetir las respuestas correctas que se han dado hace mucho tiempo sin agregar ningún valor adicional
Forraje

-1

si estás leyendo un archivo, esto puede ayudarte

              try{
             InputStream inputStream = (InputStream) mnpMainBean.getUploadedBulk().getInputStream();
             BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
             String line;
             //Ref:03
             while ((line = br.readLine()) != null) {
                if (line.matches("[A-Z],\\d,(\\d*,){2}(\\s*\\d*\\|\\d*:)+")) {
                     String[] splitRecord = line.split(",");
                     //do something
                 }
                 else{
                     br.close();
                     //error
                     return;
                 }
             }
                br.close();

             }
         }
         catch (IOException  ioExpception){
             logger.logDebug("Exception " + ioExpception.getStackTrace());
         }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.