Regex negative lookbehind no válido en JavaScript

Considerar:

var re = /(?<=foo)bar/gi; 

Es una expresión regular no válida en Plunker. ¿Por qué?

JavaScript carece de soporte para lookbehinds como (?<=…) (positivo) y (? (negativo), pero eso no significa que aún no pueda implementar este tipo de lógica en JavaScript.

Emparejamiento (no global)

Aspecto positivo detrás de la mira:

 // from /(?<=foo)bar/i var matcher = mystring.match( /foo(bar)/i ); if (matcher) { // do stuff with matcher[1] which is the part that matches "bar" } 

Contraste de aspecto negativo de ancho fijo detrás:

 // from /(? 

Las vistas negativas detrás se pueden hacer sin la bandera global, pero solo con un ancho fijo, y usted tiene que calcular ese ancho (que puede ser difícil con las alternancias ). Usar (?!foo).{3}(bar) sería más simple y más o menos equivalente, pero no coincidirá con una línea que comience con "barras de refuerzo" ya que . no puede coincidir con las nuevas líneas, por lo que necesitamos la alternancia del código anterior para hacer coincidir las líneas con "barra" antes del carácter cuatro.

Si lo necesita con un ancho variable, use la solución global a continuación y ponga un break al final de la estrofa. (Esta limitación es bastante común .NET , vim y JGsoft son los únicos motores regex que admiten ancho de banda variable detrás. PCRE , PHP y Perl están limitados al ancho fijo. Python requiere un módulo regex alternativo para admitir esto. la lógica de la solución a continuación debería funcionar para todos los idiomas que admiten expresiones regulares).

Emparejamiento (global)

Cuando necesita repetir cada coincidencia en una cadena dada (el modificador g , concordancia global), debe redefinir la variable de matcher en cada iteración de bucle y debe usar RegExp.exec() (con el RegExp creado antes del bucle ) porque String.match() interpreta el modificador global de manera diferente y creará un ciclo infinito.

Mirada positiva global detrás:

 var re = /foo(bar)/gi; // from /(?<=foo)bar/gi while ( matcher = re.exec(mystring) ) { // do stuff with matcher[1] which is the part that matches "bar" } 

"Cosas" puede, por supuesto, incluir una matriz para su uso posterior.

Global Negative lookbehind:

 var re = /(foo)?bar/gi; // from /(? 

Tenga en cuenta que hay casos en los que esto no representará completamente el aspecto negativo detrás. Considere la posibilidad de /(? contra Fall ball bill balll llama . Solo encontrará tres de las cuatro coincidencias deseadas porque cuando analiza balll , encuentra la ball y luego continúa con un personaje más tarde en l llama . Esto solo ocurre cuando una coincidencia parcial al final podría interferir con una coincidencia parcial en un final diferente (saltos de balll (ba)?ll pero foobarbar está bien con (foo)?bar ) La única solución para esto es usar lo anterior arreglado método de ancho

Reemplazando

Hay un artículo maravilloso llamado Mimicking Lookbehind en JavaScript que describe cómo hacer esto.
Incluso tiene un seguimiento que apunta a una colección de funciones cortas que implementan esto en JS.

La implementación de lookbehind en String.replace() es mucho más fácil ya que puede crear una función anónima como reemplazo y manejar la lógica de búsqueda subyacente en esa función.

Funcionan en la primera coincidencia, pero se pueden hacer globales simplemente agregando el modificador g .

Mirada positiva detrás de reemplazo:

 // assuming you wanted mystring.replace(/(?<=foo)bar/i, "baz"): mystring = mystring.replace( /(foo)?bar/i, function ($0, $1) { return ($1 ? $1 + "baz" : $0) } ); 

Esto toma la cadena objective y reemplaza instancias de bar con baz siempre y cuando sigan a foo . Si lo hacen, $1 se empareja y el operador ternario ( ?: Devuelve el texto coincidente y el texto de reemplazo (pero no la parte del bar ). De lo contrario, el operador ternario devuelve el texto original.

Mirada negativa detrás de reemplazo:

 // assuming you wanted mystring.replace(/(? 

Esto es esencialmente lo mismo, pero dado que se trata de un aspecto negativo, actúa cuando falta $1 (no necesitamos decir $1 + "baz" aquí porque sabemos que $1 está vacío).

Tiene la misma advertencia que la otra solución alternativa de ancho de banda dynamic y se soluciona de manera similar mediante el método de ancho fijo.

Esta es una forma de analizar cadena HTML usando DOM en JS y realizar reemplazos solo fuera de las tags:

 var s = '55 2 >= 1 2 > 1'; var doc = document.createDocumentFragment(); var wrapper = document.createElement('myelt'); wrapper.innerHTML = s; doc.appendChild( wrapper ); function textNodesUnder(el){ var n, walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false); while(n=walk.nextNode()) { if (n.parentNode.nodeName.toLowerCase() === 'myelt') n.nodeValue = n.nodeValue.replace(/>=?/g, "EQUAL"); } return el.firstChild.innerHTML; } var res = textNodesUnder(doc); console.log(res); alert(res);