JavaScript - backreferences de cadenas de expresiones regulares

93

Puede hacer una referencia inversa como esta en JavaScript:

var str = "123 $test 123";
str = str.replace(/(\$)([a-z]+)/gi, "$2");

Esto (bastante tonto) reemplazaría "$ test" por "test". Pero imagina que me gustaría pasar la cadena resultante de $ 2 a una función, que devuelve otro valor. Intenté hacer esto, pero en lugar de obtener la cadena "prueba", obtengo "$ 2". ¿Hay una manera de lograr esto?

// Instead of getting "$2" passed into somefunc, I want "test"
// (i.e. the result of the regex)
str = str.replace(/(\$)([a-z]+)/gi, somefunc("$2"));
quano
fuente

Respuestas:

117

Me gusta esto:

str.replace(regex, function(match, $1, $2, offset, original) { return someFunc($2); })
SLaks
fuente
1
Genial, ¿dónde puedo encontrar más información sobre esto?
Quano
11
Frio. Para aclarar: $1y $2son los nombres de los parámetros elegidos por el usuario aquí (elegidos para imitar los símbolos de referencia inversa); el - ¡variando! - el número de estos parámetros corresponde al número de grupos de captura en la expresión regular.
mklement0
34

Pase una función como segundo argumento a replace:

str = str.replace(/(\$)([a-z]+)/gi, myReplace);

function myReplace(str, group1, group2) {
    return "+" + group2 + "+";
}

Esta capacidad ha existido desde Javascript 1.3, según mozilla.org .

Sean
fuente
1

Usando ESNext, todo un sustituto de enlaces ficticios, pero solo para mostrar cómo funciona:

let text = 'Visit http://lovecats.com/new-posts/ and https://lovedogs.com/best-dogs NOW !';

text = text.replace(/(https?:\/\/[^ ]+)/g, (match, link) => {
  // remove ending slash if there is one
  link = link.replace(/\/?$/, '');
  
  return `<a href="${link}" target="_blank">${link.substr(link.lastIndexOf('/') +1)}</a>`;
});

document.body.innerHTML = text;

vdegenne
fuente
0

Nota: En la respuesta anterior faltaba algún código. Ahora es fijo + ejemplo.


Necesitaba algo un poco más flexible para un reemplazo de expresiones regulares para decodificar el Unicode en mis datos JSON entrantes:

var text = "some string with an encoded '&#115;' in it";

text.replace(/&#(\d+);/g, function() {
  return String.fromCharCode(arguments[1]);
});

// "some string with an encoded 's' in it"
Jacksonkr
fuente
0

Si tuviera una cantidad variable de referencias inversas, entonces el recuento de argumentos (y los lugares) también son variables. Los documentos web de MDN describen la siguiente sintaxis para separar una función como argumento de reemplazo:

function replacer(match[, p1[, p2[, p...]]], offset, string)

Por ejemplo, tome estas expresiones regulares:

var searches = [
    'test([1-3]){1,3}',  // 1 backreference
    '([Ss]ome) ([A-z]+) chars',  // 2 backreferences
    '([Mm][a@]ny) ([Mm][0o]r[3e]) ([Ww][0o]rd[5s])'  // 3 backreferences
];
for (var i in searches) {
    "Some string chars and many m0re w0rds in this test123".replace(
        new RegExp(
            searches[i]
            function(...args) {
                var match = args[0];
                var backrefs = args.slice(1, args.length - 2);
                // will be: ['Some', 'string'], ['many', 'm0re', 'w0rds'], ['123']
                var offset = args[args.length - 2];
                var string = args[args.length - 1];
            }
        )
    );
}

No puede usar la variable 'argumentos' aquí porque es de tipo Argumentsy no de tipo, Arraypor lo que no tiene un slice()método.

7ochem
fuente