remove - Javascript: ¿aspecto negativo equivalente?
remove class javascript (11)
Como Javascript admite una búsqueda negativa , una forma segura de hacerlo es:
Digamos que quieres echar un vistazo atrás como este
(?<!([abcdefg]))m
- Invierta la cuerda para unir
Aplica tu patrón "invertido" usando un lookahead (ten cuidado con la expresión de coincidencia invertida dentro del lookahead, en este caso, permanece igual)
m(?!([abcdefg]))
revertir todos los tokens combinados
Ejemplos:
Defino las siguientes funciones:
const reverse = s => s.split('''').reverse().join('''');
const test = (stringToTests, reversedRegexp) => stringToTests
.map(reverse)
.forEach((s,i) => {
const match = reversedRegexp.test(s);
console.log(
stringToTests[i],
match,
''token:'',
match ? reverse(reversedRegexp.exec(s)[0]) : ''Ø''
);
});
Ejemplo 1:
Siguiendo la pregunta de @andrew-ensley:
test([''jim'', ''m'', ''jam''], /m(?!([abcdefg]))/)
Productos:
jim true token: m
m true token: m
jam false token: Ø
Ejemplo 2:
Siguiendo @neaumusic comment (match max-height
pero no line-height
, el token es height
):
test([''max-height'', ''line-height''], /thgieh(?!(-enil))/)
Productos:
max-height true token: height
line-height false token: Ø
¿Hay alguna manera de lograr el equivalente de un lookbehind negativo en las expresiones regulares de JavaScript? Necesito hacer coincidir una cadena que no comienza con un conjunto específico de caracteres.
Parece que no puedo encontrar una expresión regular que haga esto sin fallar si la parte coincidente se encuentra al principio de la cadena. Las imágenes negativas parecen ser la única respuesta, pero JavaScript no tiene una.
EDITAR: Esta es la expresión regular que me gustaría trabajar, pero no:
(?<!([abcdefg]))m
Por lo tanto, coincidiría con la ''m'' en ''jim'' o ''m'', pero no con ''jam''
Esto efectivamente lo hace
"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null
Buscar y reemplazar ejemplo
"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"
Tenga en cuenta que la cadena de aspecto negativo debe tener 1 carácter para que funcione.
Esto podría ayudar, dependiendo del contexto:
Esto coincide con el m en jim pero no en el atasco:
"jim jam".replace(/[a-g]m/g, "").match(/m/g)
La estrategia de Mijoja funciona para su caso específico pero no en general:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
function($0,$1){ return $1?$0:"[match]";});
Fa[match] ball bi[match] balll [match]ama
Aquí hay un ejemplo donde el objetivo es hacer coincidir un doble-l pero no si está precedido por "ba". Tenga en cuenta la palabra "balll" - verdadero lookbehind debería haber suprimido los primeros 2 l''s, pero coincidió con el segundo par. Pero al hacer coincidir los primeros 2 l''s y luego ignorar esa coincidencia como un falso positivo, el motor de expresiones regulares continúa desde el final de ese partido e ignora cualquier carácter dentro del falso positivo.
Podrías definir un grupo que no captura al negar tu juego de caracteres:
(?:[^a-g])m
... que coincidiría con cada m
NO precedido por ninguna de esas letras.
Supongamos que quiere encontrar todo int
no precedido por unsigned
:
Con soporte para look-back negativo:
(?<!unsigned )int
Sin soporte para look-behind negativo:
((?!unsigned ).{9}|^.{0,8})int
Básicamente, la idea es tomar n caracteres precedentes y excluir la coincidencia con una anticipación negativa, pero también coincidir con los casos en los que no hay caracteres n previos. (donde n es la longitud de mirar hacia atrás).
Entonces la expresión regular en cuestión:
(?<!([abcdefg]))m
se traduciría a:
((?!([abcdefg])).|^)m
Es posible que necesite jugar con grupos de captura para encontrar el punto exacto de la cadena que le interese o si desea reemplazar una parte específica por otra.
Usando su caso, si quiere reemplazar m
por algo, por ejemplo, convertirlo a M
mayúscula, puede negar el conjunto en el grupo de captura.
match ([^ag])m
, reemplace con $1M
"jim jam".replace(/([^a-g])m/g, "$1M")
//jiM jam
([^ag])
hará coincidir cualquier char no ( ^
) en un rango ag
, y lo almacenará en el primer grupo de captura, para que pueda acceder a él con $1
.
Así que encontramos im
in jim
y lo reemplazo con iM
que da como resultado jiM
.
Utilizar
newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:''m'';});
siguiendo la idea de Mijoja y extrayendo los problemas expuestos por JasonS, tuve esta idea; He verificado un poco, pero no estoy seguro de mí mismo, por lo que una verificación por alguien más experto que yo en js regex sería genial :)
var re = /(?=(..|^.?)(ll))/g
// matches empty string position
// whenever this position is followed by
// a string of length equal or inferior (in case of "^")
// to "lookbehind" value
// + actual value we would want to match
, str = "Fall ball bill balll llama"
, str_done = str
, len_difference = 0
, doer = function (where_in_str, to_replace)
{
str_done = str_done.slice(0, where_in_str + len_difference)
+ "[match]"
+ str_done.slice(where_in_str + len_difference + to_replace.length)
len_difference = str_done.length - str.length
/* if str smaller:
len_difference will be positive
else will be negative
*/
} /* the actual function that would do whatever we want to do
with the matches;
this above is only an example from Jason''s */
/* function input of .replace(),
only there to test the value of $behind
and if negative, call doer() with interesting parameters */
, checker = function ($match, $behind, $after, $where, $str)
{
if ($behind !== "ba")
doer
(
$where + $behind.length
, $after
/* one will choose the interesting arguments
to give to the doer, it''s only an example */
)
return $match // empty string anyhow, but well
}
str.replace(re, checker)
console.log(str_done)
mi salida personal:
Fa[match] ball bi[match] bal[match] [match]ama
el principio es llamar al checker
en cada punto de la cadena entre dos caracteres cualquiera, siempre que esa posición sea el punto de partida de:
--- cualquier subcadena del tamaño de lo que no se quiere (aquí ''ba''
, así ..
) (si ese tamaño es conocido, de lo contrario, debe ser más difícil hacerlo tal vez)
--- --- o más pequeño que eso si es el comienzo de la cadena: ^.?
y, siguiendo esto,
--- lo que realmente se busca (aquí ''ll''
).
En cada llamada de checker
, habrá una prueba para verificar si el valor anterior a ll
no es lo que no queremos ( !== ''ba''
); si ese es el caso, llamamos a otra función, y tendrá que ser ésta ( doer
) que hará los cambios en str, si el propósito es este, o más genéricamente, que ingresará los datos necesarios para manualmente procesar los resultados del escaneo de str
.
aquí cambiamos la cadena, así que necesitamos mantener un rastro de la diferencia de longitud para compensar las ubicaciones dadas por replace
, todo calculado en str
, que en sí mismo nunca cambia.
Como las cadenas primitivas son inmutables, podríamos haber usado la variable str
para almacenar el resultado de toda la operación, pero pensé que el ejemplo, ya complicado por las sustituciones, sería más claro con otra variable ( str_done
).
Supongo que en términos de rendimiento debe ser bastante duro: todos esos reemplazos sin sentido de '''' en '''', this str.length-1
veces, más aquí reemplazo manual por hacedor, lo que significa un montón de rebanado ... probablemente en este caso específico anterior que podría agruparse, cortando la cuerda solo una vez en trozos alrededor de donde queremos insertar [match]
y .join()
ing con [match]
sí mismo.
la otra cosa es que no sé cómo manejaría los casos más complejos, es decir, los valores complejos para el falso aspecto ... la longitud tal vez sea la información más problemática para obtener.
y, en el checker
, en caso de múltiples posibilidades de valores no deseados por $ atrás, tendremos que hacer una prueba con otra expresión regular (para ser almacenado en caché (creado) fuera de la mejor checker
, para evitar el mismo objeto regex para se creará en cada llamada para checker
) para saber si es o no lo que tratamos de evitar.
espero que haya sido claro; si no, no lo dudes, lo intentaré mejor. :)
Lookbehind Assertions fue accepted en la especificación ECMAScript en 2018. Esto se implementó en V8 y se envió sin marcas con Google Chrome v62 y en Node.js v6 detrás de una bandera y v9 sin una bandera . Por lo tanto, si está desarrollando para un entorno exclusivo de Chrome (como Electron ) o Node , ¡puede comenzar a utilizar lookbehinds hoy mismo!
Uso de la mirada positiva detrás:
console.log(
"$9.99 €8.47".match(/(?<=/$)/d+(/./d*)?/) // Matches "9.99"
);
Negativo lookbehind uso:
console.log(
"$9.99 €8.47".match(/(?<!/$)/d+(?:/./d*)/) // Matches "8.47"
);
Soporte en otras plataformas:
- Error de implementación de Mozilla Firefox.
- suggestion implementación de Microsoft Edge.
/(?![abcdefg])[^abcdefg]m/gi
sí, esto es un truco.