RegEx para extraer todas las coincidencias de la cadena usando RegExp.exec

8 minutos de lectura

RegEx para extraer todas las coincidencias de la cadena usando
gatlín

Estoy tratando de analizar el siguiente tipo de cadena:

[key:"val" key2:"val2"]

donde hay claves arbitrarias: pares “val” dentro. Quiero tomar el nombre de la clave y el valor. Para aquellos curiosos, estoy tratando de analizar el formato de la base de datos de Task Warrior.

Aquí está mi cadena de prueba:

[description:"aoeu" uuid:"123sth"]

lo que pretende resaltar que cualquier cosa puede estar en una clave o valor aparte del espacio, sin espacios alrededor de los dos puntos, y los valores siempre están entre comillas dobles.

En el nodo, esta es mi salida:

[deuteronomy][gatlin][~]$ node
> var re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
> re.exec('[description:"aoeu" uuid:"123sth"]');
[ '[description:"aoeu" uuid:"123sth"]',
  'uuid',
  '123sth',
  index: 0,
  input: '[description:"aoeu" uuid:"123sth"]' ]

Pero description:"aoeu" también coincide con este patrón. ¿Cómo puedo recuperar todos los partidos?

  • Puede ser que mi expresión regular sea incorrecta y/o que simplemente esté usando incorrectamente las funciones de expresión regular en JavaScript. Esto parece funcionar: > var s = “Quince es 15 y ocho es 8”; > var re = /\d+/g; > var m = s.match(re); metro = [ ’15’, ‘8’ ]

    – Gatlin

    12 de junio de 2011 a las 18:08


  • Javascript ahora tiene una función .match(): desarrollador.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Usado así: "some string".match(/regex/g)

    – Stefnotch

    5 de marzo de 2016 a las 9:37

RegEx para extraer todas las coincidencias de la cadena usando
mar de césped

Continuar llamando re.exec(s) en un bucle para obtener todas las coincidencias:

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s="[description:"aoeu" uuid:"123sth"]";
var m;

do {
    m = re.exec(s);
    if (m) {
        console.log(m[1], m[2]);
    }
} while (m);

Pruébelo con este JSFiddle: https://jsfiddle.net/7yS2V/

  • Por qué no while en lugar de do … while?

    – Gumbo

    12 de junio de 2011 a las 18:14

  • El uso de un bucle while hace que sea un poco incómodo inicializar m. O tienes que escribir while(m = re.exec(s))que es una OMI antipatrón, o tienes que escribir m = re.exec(s); while (m) { ... m = re.exec(s); }. Prefiero el do ... if ... while idioma, pero otras técnicas también funcionarían.

    – mar de césped

    12 de junio de 2011 a las 18:21

  • hacer esto en cromo provocó que mi pestaña se bloqueara.

    – EdgeCaseBerg

    16 de diciembre de 2014 a las 18:53

  • @EdgeCaseBerg Necesitas tener el g indicador establecido, de lo contrario, el puntero interno no se mueve hacia adelante. Documentos.

    – Tim

    25 de julio de 2015 a las 13:45

  • Otro punto es que si la expresión regular puede coincidir con una cadena vacía, será un bucle infinito

    – Fabio Costa

    8 de junio de 2017 a las 0:57

1646751070 714 RegEx para extraer todas las coincidencias de la cadena usando
anís

str.match(pattern)si pattern tiene la bandera mundial gdevolverá todas las coincidencias como una matriz.

Por ejemplo:

const str="All of us except @Emran, @Raju and @Noman were there";
console.log(
  str.match(/@\w*/g)
);
// Will log ["@Emran", "@Raju", "@Noman"]

  • Cuidado: las coincidencias no son objetos de coincidencia, sino cadenas coincidentes. Por ejemplo, no hay acceso a los grupos en "All of us except @Emran:emran26, @Raju:raju13 and @Noman:noman42".match(/@(\w+):(\w+)/g) (que volverá ["@Emran:emran26", "@Raju:raju13", "@Noman:noman42"])

    – madprog

    18 de agosto de 2017 a las 9:46


  • @madprog, correcto, es la forma más fácil pero no adecuada cuando los valores del grupo son esenciales.

    – Anís

    13 de septiembre de 2017 a las 10:02

  • Esto no funciona para mí. Solo obtengo el primer partido.

    –Anthony Roberts

    31 de diciembre de 2018 a las 19:38

  • @AnthonyRoberts debe agregar la bandera “g”. /@\w/g o new RegExp("@\\w", "g")

    – Aruna Herath

    28 de enero de 2019 a las 7:50

1646751071 493 RegEx para extraer todas las coincidencias de la cadena usando
Cristóbal

Para recorrer todas las coincidencias, puede usar el replace función:

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s="[description:"aoeu" uuid:"123sth"]";

s.replace(re, function(match, g1, g2) { console.log(g1, g2); });

  • Creo que es demasiado complicado. Sin embargo, es bueno conocer las diferentes formas de hacer algo simple (voto tu respuesta).

    – Arashsoft

    12 mayo 2016 a las 21:09

  • Es un código contrario a la intuición. No está “reemplazando” nada en ningún sentido significativo. Es solo explotar alguna función para un propósito diferente.

    – Lucas Maurer

    27 de julio de 2017 a las 19:43

  • @dudewad si los ingenieros simplemente siguieran las reglas sin pensar fuera de la caja, ni siquiera estaríamos pensando en visitar otros planetas en este momento 😉

    – Cristóbal

    7 sep 2018 a las 22:56

  • @dudewad lo siento, no veo la parte perezosa aquí. Si exactamente el mismo método se llamara “proceso” en lugar de “reemplazar”, estaría de acuerdo con él. Me temo que estás atascado en la terminología.

    – Cristóbal

    16/09/2018 a las 23:43

  • @Christophe Definitivamente no estoy atascado en la terminología. Estoy atascado en código limpio. Usar cosas que están destinadas para un propósito para un propósito diferente se llama “hacky” por una razón. Crea un código confuso que es difícil de entender y, en la mayoría de los casos, sufre en cuanto al rendimiento. El hecho de que haya respondido esta pregunta sin una expresión regular en sí misma la convierte en una respuesta no válida, ya que el OP pregunta cómo hacerlo con expresiones regulares. Sin embargo, me parece importante mantener a esta comunidad en un nivel alto, por lo que mantengo lo que dije anteriormente.

    – amigo

    19 de septiembre de 2018 a las 7:54

RegEx para extraer todas las coincidencias de la cadena usando
lovasoa

esta es una solucion

var s="[description:"aoeu" uuid:"123sth"]";

var re = /\s*([^[:]+):\"([^"]+)"/g;
var m;
while (m = re.exec(s)) {
  console.log(m[1], m[2]);
}

Esto se basa en la respuesta de Lawnsea, pero más corta.

Tenga en cuenta que la bandera ‘g’ debe establecerse para mover el puntero interno hacia adelante a través de las invocaciones.

1646751072 610 RegEx para extraer todas las coincidencias de la cadena usando
eaorak

str.match(/regex/g)

devuelve todas las coincidencias como una matriz.

Si, por alguna razón misteriosa, necesita la información adicional que viene con execcomo alternativa a las respuestas anteriores, podría hacerlo con una función recursiva en lugar de un bucle de la siguiente manera (que también se ve mejor :).

function findMatches(regex, str, matches = []) {
   const res = regex.exec(str)
   res && matches.push(res) && findMatches(regex, str, matches)
   return matches
}

// Usage
const matches = findMatches(/regex/g, str)

como se indicó en los comentarios anteriores, es importante tener g al final de la definición de expresiones regulares para mover el puntero hacia adelante en cada ejecución.

  • si. recursivo se ve elegante y más fresco. Los bucles iterativos son sencillos, más fáciles de mantener y depurar.

    – Andy N.

    5 abr 2019 a las 22:49

  • Me encantan las soluciones recursivas porque; Me encantan las soluciones recursivas

    – Ben bobinado

    17 de diciembre de 2020 a las 4:28

Finalmente estamos comenzando a ver una función integrada matchAll función, ver aquí para la descripción y la tabla de compatibilidad. Parece que a partir de mayo de 2020, se admiten Chrome, Edge, Firefox y Node.js (12+), pero no IE, Safari y Opera. parece que fue redactado en diciembre de 2018 así que dale algo de tiempo para que llegue a todos los navegadores, pero confío en que llegará allí.

el incorporado matchAll La función es agradable porque devuelve un iterable. ¡También regresa capturando grupos para cada partido! Entonces puedes hacer cosas como

// get the letters before and after "o"
let matches = "stackoverflow".matchAll(/(\w)o(\w)/g);

for (match of matches) {
    console.log("letter before:" + match[1]);
    console.log("letter after:" + match[2]);
}

arrayOfAllMatches = [...matches]; // you can also turn the iterable into an array

También parece que cada objeto de coincidencia usa el mismo formato que match(). Entonces, cada objeto es una matriz de los grupos de coincidencia y captura, junto con tres propiedades adicionales index, inputy groups. Así que parece:

[<match>, <group1>, <group2>, ..., index: <match offset>, input: <original string>, groups: <named capture groups>]

Para más información sobre matchAll también hay una Página de desarrolladores de Google. también hay rellenos de polietileno/calzas disponible.

  • si. recursivo se ve elegante y más fresco. Los bucles iterativos son sencillos, más fáciles de mantener y depurar.

    – Andy N.

    5 abr 2019 a las 22:49

  • Me encantan las soluciones recursivas porque; Me encantan las soluciones recursivas

    – Ben bobinado

    17 de diciembre de 2020 a las 4:28

Si tienes ES9

(Es decir, si su sistema: Chrome, Node.js, Firefox, etc. es compatible con Ecmascript 2019 o posterior)

Usa el nuevo yourString.matchAll( /your-regex/ ).

Si no tienes ES9

Si tiene un sistema antiguo, aquí hay una función para copiar y pegar fácilmente

function findAll(regexPattern, sourceString) {
    let output = []
    let match
    // make sure the pattern has the global flag
    let regexPatternWithGlobal = RegExp(regexPattern,[...new Set("g"+regexPattern.flags)].join(""))
    while (match = regexPatternWithGlobal.exec(sourceString)) {
        // get rid of the string copy
        delete match.input
        // store the match data
        output.push(match)
    } 
    return output
}

ejemplo de uso:

console.log(   findAll(/blah/g,'blah1 blah2')   ) 

salidas:

[ [ 'blah', index: 0 ], [ 'blah', index: 6 ] ]

  • Con la mayoría de los navegadores compatibles str.matchAll esta respuesta debe estar en la lista superior

    – Amit

    3 ene a las 15:30

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad