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].

Craig Walker
fuente
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+).*
Allain Lalonde
fuente
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
javaMan
fuente
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.

Axeman
fuente
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.

Vitalii Fedorenko
fuente
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);
}
Jack Leow
fuente
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 = "[email protected], <[email protected]>>>> [email protected]"ello creará la Lista de 3 elementos.

LukaszTaraszka
fuente
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));
}
Tinte Naing Win
fuente
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);
Pan comido
fuente
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)

shounak
fuente
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.

arturo
fuente
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]
usuario1722707
fuente
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);
}
Mohammadreza Tavakoli
fuente
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());
         }
buscador
fuente