0

Tengo 2 patrones:

var a = /[^+][a-zA-Z]/;
var b = /[a-zA-Z][^+]/;

Según fuentes que he leído, lo que hace el patrón a, es negar con ^ el caracter +, pero no debería escaparlo ?, quedando:

[^\+]

Además el patrón b, hace lo mismo pero al final, no debería ser $[^+], por que $ es para el final? y viceversa con el patron a, el cual debería ser ^[^+] ? Por qué no es así?

PD: en sí la pregunta va dirigida a que el patrón funciona, aún asi cuando no escapa el +, ni tampoco usa ^[^+] ni $[^+], ya que eso tenía entendido del funcionamiento YO, de la regex

Mariano
  • 23,777
  • 20
  • 70
  • 102
Eduardo Sebastian
  • 4,908
  • 7
  • 30
  • 70
  • Siento que está muy amplia la pregunta y hay cosas que estás dejando a deducción de quien lee. Por ejemplo ¿Qué es lo que esperas hacer con los patrones? y ¿Cómo y porqué no hacen lo que tú quieres que hagan?, o colocar ejemplos donde el problema que comentas se reproduzca, poniendo lo que esperas que hagan las expresiones, y el resultado que en realidad te está enviando. – Yikarus Nov 13 '17 at 22:52
  • editado, Yikarus – Eduardo Sebastian Nov 13 '17 at 22:56
  • `[^+]` y `[^\+]` son equivalentes, en ambos casos la expresión buscará elementos que no contengan el signo de más. Al ser un cuantificador `+` para que este sea tomado como tal por la expresión, tiene que estar a la derecha de algún caracter `abc+` o expresión `[a-zA-Z]+` , indicando que puede buscar `uno o más` – Yikarus Nov 13 '17 at 23:09
  • Los caracteres `^ y $` indican el inicio y fin de un string, esto es para dar un límite exacto a la expresión de lo que quieres buscar, y esta sólo buscara el primer elemento que encuentre y cumpla con las condiciones – Yikarus Nov 13 '17 at 23:13

2 Answers2

4

Hay varios conceptos a corregir sobre lo que estás interpretando:

  • Una clase de caracteres (entre corchetes) coincide con un, y sólo un, caracter. No importa si está negado o no, siempre coincide con un caracter.

  • Si bien es necesario escapar los metacaracteres en regex, no es necesario escapar a la mayoría dentro de una clase de caracteres. Los únicos 3 que es necesario escapar entre corchetes son:

    • ^ cuando está al principio, para evitar que niegue a la clase.
    • - en el medio, para evitar que construya un rango.
    • \ porque se usa para escapar a otros caracteres.
    • ] para evitar que cierre la clase.

    Es decir que [^+] y [^\+] son exactamente lo mismo.

  • Los dos patrones no coinciden con lo mismo. No es lo mismo:

    • /[^+][a-zA-Z]/ ::: un caracter (cualquiera excepto un +), seguido de otro caracter alfabético, que
    • /[a-zA-Z][^+]/ ::: un caracter alfabético seguido de otro caracter (cualquiera excepto un +).

    Por ejemplo, el primer patrón coincide con el texto "@m", pero el segundo patrón no. Nótese cómo [^+] coincide con la @, claro, porque es un caracter que no es un +.

  • ^ coincide con la posición al inicio del texto, y $ coincide con la posición al final del texto. Y estoy haciendo énfasis en posición porque eso es lo que deberías pensar al utilizarlos. Por ejemplo, no es correcto lo que comentaste: $[^+] significa la posición final del texto y luego un caracter cualquiera excepto un +... no va a coincidir jamás, con nada, es imposible. La posición final del texto no puede estar seguida por otro caracter.

  • Como no estás utilizando ^ ni $, ambos patrones van a intentar coincidir con 2 caracteres en cualquier posición del texto. Por ejemplo, ambos patrones van a coincidir con el texto "+++86gg99+++", pero cada uno va a coincidir con partes diferentes de ese texto. ¿Podés intentar adivinar con qué 2 caracteres va a coincidir cada uno?

    //Esta es la respuesta
    
    var a = /[^+][a-zA-Z]/,
        b = /[a-zA-Z][^+]/,
        texto = "+++86gg99+++";
    
    console.log(a.source, "coincide con", texto.match(a));
    console.log(b.source, "coincide con", texto.match(b));
Mariano
  • 23,777
  • 20
  • 70
  • 102
2

Primero hay que empezar por lo que hace tu patrón:

var a = '[^+][a-zA-Z]'
var reg = new RegExp(a);
console.log(reg.test('aA'));
console.log(reg.test('+aA'));

Este busca cualquier coincidencia en un string que contenga: [cualquier caracter que no sea '+'] y [cualquier caracter que esté entre a-z o A-Z]

Algunos ejemplos de strings que encontrará tu patrón: 'aF', 'eC', '3V', '.a' En esta liga puedes ver los patrones que encuentra la expresión, además de que la uso mucho cuando trabajo con expresiones regulares: https://regexr.com/3h5tb

Ahora tu primer pregunta: ¿Escapar o no el signo de más: [^\+]? Como tal no es necesario ya que si haces la prueba ambas expresiones son equivalentes y te darán el mismo resultado:

var a = '[^\+][a-zA-Z]'
var reg = new RegExp(a);
console.log(reg.test('aA'));

Esto es principalmente porque dentro de esa expresión el signo de más se toma como lo es, un caracter de signo de más, y no como un cuantificador como una expresión regular acostumbra usarlo, para eso este elemento tendría que ir a la derecha de algún caracter donde requieras buscar uno o más, o a la derecha de una expresión donde de igual forma requieras buscar uno o más ejemplo:

var a = '[^+]+[a-zA-Z]'
var b = '[^+][a-zA-Z]+'
var reg = new RegExp(a);
var regB = new RegExp(b);
console.log(reg.test('aaA'));
console.log(regB.test('icCdfe'));

Aquí también el ejemplo en la liga con patrón b de este ejemplo, y si te fijas ahora busca cadenas más largas, por el cuantificador +: http://regexr.com/3h5te

La segunda pregunta: ¿Usar ^ y $? Estos símbolos indican a la expresión el inicio y el fin de la cadena que la expresión debe de buscar, lo que aquí si hay que hacer énfasis es que estás dando un inicio y fin, por lo que cualquier cosa que esté antes o después de tu string que estás buscando ocasionará que tu expresión no lo encuentre al no cumplir con los patrones, ejemplo:

var a = '^[^+][a-zA-Z]$'
var reg = new RegExp(a);
console.log(reg.test('aA'));
console.log(reg.test('+a')); //Caracter '+' por lo que falla
console.log(reg.test('+aA')); //Caracter '+' pero usas ^$ por lo que aún falla, aunque en los primeros ejemplos si funcione

Con esto podemos decir que al usar ^ $ acotas el patrón de búsqueda a un resultado y que este sea exacto y cumpla con la condición de la expresión, de no usarlo como en los primeros ejemplos, aunque encuentre un signo de más, sigue encontrando una pareja de caracteres que cumplen con tu condición y la prueba te regresa true

Yikarus
  • 1,827
  • 6
  • 15
  • Buena respuesta, pero evitaría usar el constructor (`new RegExp()`) innecesariamente. En especial, porque en tu 2do ejemplo el `\+` en realidad lo estás pasando sin la barra (por más que no haya diferencia como bien explicaste, la demostración no está bien). – Mariano Nov 14 '17 at 00:29
  • Entendido y anotado – Yikarus Nov 14 '17 at 00:30