Eliminar patrones anidados con una línea de JavaScript

He aquí un pequeño truco que se me ocurrió para eliminar patrones anidados de una cadena.

var str = "abc<1<2<>3>4>def";

while (str != (str = str.replace(/<[^<>]*>/g, "")));

// str -> "abcdef"

Tenga en cuenta que la expresión regular en este one-liner no trata de tratar con patrones anidados en absoluto. El while la condición del bucle reemplaza las instancias de <…> (donde los corchetes angulares no están permitidos en el patrón interno) con una cadena vacía. Esto se repite de adentro hacia afuera, hasta que la expresión regular ya no coincida. En ese punto, el resultado del reemplazo es el mismo que el de la cadena en cuestión y el ciclo finaliza.

Puede usar un enfoque similar para obtener patrones anidados en lugar de eliminarlos, como se muestra a continuación.

[Editar (6/6/2008): El siguiente código no maneja correctamente entradas como "((a)(b))". Si explora la recursividad de etiquetas en este blog, encontrará una variedad de otros enfoques para hacer coincidir construcciones anidadas que realmente funcionan correctamente.]

var str = "abc(d(e())f)(gh)ijk()",
    re = /\([^()]*\)/,
    output = [],
    match, parts, last;

while (match = re.exec(str)) {
    parts = match[0].split("\uFFFF");
    if (parts.length < 2) {
        last = output.push(match[0]) - 1;
    } else {
        output[last] = parts[0] + output[last] + parts[1];
    }
    str = str.replace(re, "\uFFFF");
}

// output -> ["(d(e())f)", "(gh)", "()"]

Dado que una vez más estamos trabajando de adentro hacia afuera, volver a ensamblar cada coincidencia completa requiere que marquemos la posición en la que se eliminó la coincidencia de nivel más profundo anterior. He usado la secuencia de escape Unicode \uFFFF para marcar tales posiciones, porque ese es un punto de código no asignado permanentemente.

Tenga en cuenta que usar una clase de carácter negado como [^()] para que coincida con el patrón interno como se muestra en los ejemplos aquí solo funciona correctamente si está utilizando delimitadores de un solo carácter como (…) o <…> . Si desea hacer coincidir/eliminar patrones anidados que usan delimitadores de varios caracteres, puede usar una expresión regular como /<<(?:(?!<<|>>)[\S\s])*>>/ . Simplemente cambie ambas instancias de << a su delimitador izquierdo, y >> a su delimitador derecho.