Pregunta Javascript Regex - Encuentra todas las coincidencias posibles, incluso en partidas ya capturadas


Estoy tratando de obtener todas las coincidencias posibles de una cadena utilizando expresiones regulares con javascript. Parece que mi método para hacer esto no coincide con partes de la cadena que ya se han emparejado.

Variables:

var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y';

var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g;

Código:

var match = string.match(reg);

Todos los resultados coincidentes que obtengo:

A1B1Y:A1B2Y
A1B5Y:A1B6Y
A1B9Y:A1B10Y

Resultados coincidentes que quiero:

A1B1Y:A1B2Y
A1B2Y:A1B3Y
A1B5Y:A1B6Y
A1B6Y:A1B7Y
A1B9Y:A1B10Y
A1B10Y:A1B11Y

En mi cabeza, quiero A1B1Y:A1B2Y para ser un partido junto con A1B2Y:A1B3Y, aunque A1B2Y en la cuerda tendrá que ser parte de dos partidos.


12
2018-02-13 21:00


origen


Respuestas:


Sin modificar su expresión regular, puede configurarla para que comience a coincidir al comienzo de la segunda mitad del partido después de cada partida usando .exec y manipulando el objeto regex lastIndex propiedad.

var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y';
var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g;
var matches = [], found;
while (found = reg.exec(string)) {
    matches.push(found[0]);
    reg.lastIndex -= found[0].split(':')[1].length;
}

console.log(matches);
//["A1B1Y:A1B2Y", "A1B2Y:A1B3Y", "A1B5Y:A1B6Y", "A1B6Y:A1B7Y", "A1B9Y:A1B10Y", "A1B10Y:A1B11Y"]

Manifestación


Según el comentario de Bergi, también puedes obtener el índice del último partido e incrementarlo en 1 por lo que en lugar de comenzar a coincidir desde la segunda mitad del partido, comenzará a intentar coincidir con el segundo personaje de cada partido en adelante. :

reg.lastIndex = found.index+1;

Manifestación

El resultado final es el mismo. Sin embargo, la actualización de Bergi tiene un poco menos de código y funciona ligeramente Más rápido. =]


21
2018-02-13 21:14



No puedes obtener el resultado directo de match, pero es posible producir el resultado a través de RegExp.exec y con algunas modificaciones a la expresión regular:

var regex = /A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g;
var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'
var arr;
var results = [];

while ((arr = regex.exec(input)) !== null) {
    results.push(arr[0] + arr[1]);
}

solía ancho cero mirada positiva hacia adelante (?=pattern) para no consumir el texto, de modo que la parte superpuesta se pueda volver a emparejar.

En realidad, es posible abusar replace método para lograr el mismo resultado:

var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'
var results = [];

input.replace(/A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g, function ($0, $1) {
    results.push($0 + $1);
    return '';
});

Sin embargo, dado que es replace, hace un trabajo de reemplazo extra inútil.


4
2018-02-13 21:15



Desafortunadamente, no es tan simple como un solo string.match.

La razón es que desea superponer coincidencias, que el /g la bandera no te da.

Puedes usar lookahead:

var re = /A\d+B\d+Y(?=:A\d+B\d+Y)/g;

Pero ahora obtienes:

string.match(re); // ["A1B1Y", "A1B2Y", "A1B5Y", "A1B6Y", "A1B9Y", "A1B10Y"]

La razón es que la búsqueda anticipada es de ancho cero, lo que significa que solo dice si el patrón viene después de lo que estás tratando de igualar o no; no lo incluye en el partido.

Podrías usar exec para tratar de agarrar lo que quieras. Si una expresión regular tiene el /g bandera, puedes correr exec repetidamente para obtener todas las coincidencias:

// using re from above to get the overlapping matches

var m;
var matches = [];
var re2 = /A\d+B\d+Y:A\d+B\d+Y/g; // make another regex to get what we need

while ((m = re.exec(string)) !== null) {
  // m is a match object, which has the index of the current match
  matches.push(string.substring(m.index).match(re2)[0]);
}

matches == [
  "A1B1Y:A1B2Y", 
  "A1B2Y:A1B3Y", 
  "A1B5Y:A1B6Y", 
  "A1B6Y:A1B7Y", 
  "A1B9Y:A1B10Y", 
  "A1B10Y:A1B11Y"
];

Aquí hay un violín de esto en acción. Abra la consola para ver los resultados

Alternativamente, podría dividir la cadena original en :, luego recorra la matriz resultante, extrayendo las que coinciden cuando array[i] y array[i+1] ambos coinciden como quieras.


3
2018-02-13 21:28