Páginas

miércoles, 24 de julio de 2024

¿Qué pasó con Windows y Crowdstrike el 19 de julio de 2024?

Después de indagar y olisquear por ahí voy a describir lo que yo creo que pasó y causó tantos problemas en aeropuertos, hospitales, oficinas gubernamentales y otras organizaciones. También voy a reflexionar sobre cómo se puede hacer para que esto no vuelva a pasar.

Descripción de los hechos

Los equipos que tenían instalado el sistema operativo Windows y la plataforma Falcon, el 19 de julio recibieron una actualización automática desde la plataforma Cloud de Crowdstrike.

Según la web de CrowdStrike, Falcon es: “Falcon es la plataforma de CrowdStrike diseñada específicamente para detener las infracciones a través de un conjunto unificado de tecnologías entregadas desde la nube que previenen todo tipo de ataques, incluido el malware y mucho más. CrowdStrike Falcon responde a esos desafíos con una solución poderosa pero liviana que unifica el antivirus de próxima generación (NGAV), la detección y respuesta de endpoints (EDR) y la detección inteligente de amenazas cibernéticas, todo contenido en un dispositivo pequeño y único, un Sensor liviano."

Gráficamente se puede organizar de esta forma:

La actualización afectó sólo a sistemas que estaban conectados a internet, tenían instalados Windows y Falcon y aceptaron la actualización automática. Estás actualizaciones forman parte del proceder habitual de Crodstrike y se suelen producir varias veces al día.

Esta actualización provocó, por un fallo software, que Falcon Agent detectase que se estaba intentando acceder a una dirección de memoria que está reservada para el sistema operativo. Esto es una violación que se interpretó como un cyberataque y causó que el sistema se intentase reiniciar para evitar males mayores.

La actualización incluía un fichero llamado C-00000291*.SYS que tenía un contenido erróneo. Falcon Agent utilizaba dicho fichero durante el pre-arranque del sistema y esto provocaba que no se pudiese llegar al arranque. Entonces Windows mostraba la pantalla azul (BSoD – Blue Screen of Dead). Por muchas veces que se intentase rearrancar, el proceso se repetía y se volvía a obtener la pantalla azul, es decir no era posible arrancar.

La solución era ir al directorio de Windows donde esta el fichero y borrarlo, después de haber arrancado en modo seguro para evitar el uso del fichero C-00000291*.SYS y no caer en el bucle de BSoD. Normalmente el fichero se aloja en el directorio C:/windows/System32/drivers.

Reflexión

Me parece muy oportuno como Freddy Vega

explica lo ocurrido e indica que, aunque alguien escribió el contenido de ese fichero y alguien escribió las lineas de código que manejan ese contenido, no es un error de una persona es un error del proceso que Crowdstrike emplea para desplegar las actualizaciones. Alguien se equivocó y el proceso de despliegue establecido por la organización no le ayudó a que se diese cuenta de su error.

A su vez es un error de los procesos de despliegue de los clientes de Crowdstrike que confían en actualizaciones automáticas de un tercero que ellos mismos no han probado ni verificado.

Existen múltiples técnicas ideadas y puestas en marcha por los departamentos de T.I. del mundo entero para evitar que pasen estas cosas. Por ejemplo los despliegues blue-green, métodos de pruebas automatizadas y no automatizadas para verificar que todo está bien antes del despliegue, sistemas de automatización del despliegue (canales DevOps) con puntos de verificación múltiples tanto de calidad del software como de verificación de funcionalidad , etc.

A pesar de todos los mecanismos que una organización emplee para evitar estos problemas el error se puede producir, pero mediante diferentes técnicas muchas organizaciones han conseguido minimizar este riesgo.

La experiencia ha demostrado que emplear recursos en organizar los procesos de los departamentos TI para mejorar el servicio a los usuarios del software y los beneficios a la organización propietaria de ese software, FUNCIONA.

Creo que es importante que los ingenieros de software sean conscientes de esto y creen procesos robustos que eviten se produzcan esto apagones que tantos problemas causan. Además que sean capaces de buscar promotores de su buen hacer en las organizaciones.

El software no es intangible, sólo su interior para los no profesionales. Seguro que a nadie le gustaría comprar una casa nueva que aparentemente es muy confortable, pero que en cuanto se habitase todo se fuese abajo: cimientos, cableados, desagües, circuito de calefacción, etc. Pues eso es lo que desde fuera no se ve pero es fundamental.

Epìlogo

A continuación enumero los lugares en los que he leído la información que aquí he sintetizado. Puede que los detalles técnicos de la Plataforma Falcon no sean exactos pero la conclusión sería la misma.

Si alguien me puede proporcionar más detalles del fallo, estaré muy agradecida y disculpas por las imprecisiones.

Plataforma Crowdstrike Para ver pulse aquí

Technical details of the Windows BSOD disaster due to CrowdStrike por B Shyam Sundar Para ver pulse aquí

Blue Screens to Blackouts: The Story Behind the CrowdStrike Outage por Animesh Gaitonde Para ver pulse aquí

lunes, 25 de septiembre de 2023

Un ejemplo de Mock Service Worker con React

Cuando se trata de hacer una aplicación web muy a menudo se utiliza un API Rest que suministra datos desde el backend. No siempre está disponible el backend en el momento en que se empieza a desarrollar el frontend o incluso a veces es deseable no depender de los vaivenes del desarrollo del backend.

Para aislar al frontend del backend es útil la librería Mock Service Worker. Mediante esta librería podemos simular el backend cómo si ya estuviese disponible aunque no lo esté. Vamos a ver un ejemplo.

Para acceder a los recursos del backend se utilizan métodos HTTP. En este ejemplo vamos a simular un get que devuelve frases famosas. El get se simula con:

Es decir, cuando desde el frontend se ejecuta el fetch que envía el get, si estamos en el entorno de desarrollo se ejecuta un get que devuelve un fichero json con estas 2 citas. Para distinguir el entorno de desarrollo del de producción se usa una variable de entorno de la siguiente manera:

https://thesimpsonsquoteapi.glitch.me/" es la url del backend real, la que se utilizará en producción cuando todo esté funcionando.

Entonces lo que es necesario para que todo esto funciones es instalar la librería Mock Service Worker con npm install msw --save-dev Y utilizar la función setupWorker con el workersetup.js con el siguiente contenido:

Bueno pongo todo en orden para que se entienda:

Main-page.js es un componente React que determina cual es la URL que se utilizará para el get como hemos visto anteriormente. El objetivo de este componente es mostrar todas las citas que devuelve el blackend. El contenido de Main-page.js es:

En este ejemplo cuando se está realizando la ejecución en el entorno de desarrollo el get se efectúa a /quotes y cuando es otro entorno, en este caso producción el get se efectúa a https://thesimpsonsquoteapi.glitch.me/quotes. Son workerSetup.js y handlers.js los que se encargan de simular la respuesta del get cuando la petición se lanza a /quotes.

Entonces lo que vemos en la pantalla cuando ejecutamos este componente en el entorno de desarrollo es:

Coincidiendo las citas que se muestran en pantalla con las que se crean en el objeto handlers.js cuyo contenido se mostró en la primera imagen de código.

Conclusión

Esta librería nos puede ayudar cuando durante el desarrollo queremos independizar el frontend del backend. Es decir podemos ir avanzando el frontend aunque el backend no esté disponible.

sábado, 12 de agosto de 2023

Un ejemplo de Cucumber para hacer BDD (Behavior driven development)

BDD tiende un puente para que los expertos del negocio y los informáticos se entiendan sin fisuras. BDD alienta la colaboración, construye compresión compartida sobre el comportamiento esperado del sistema, produce documentación que guía el desarrollo y permite validar el comportamiento del sistema de forma automática.

Trabajando en rápidos y pequeños ciclos mejora la retroalimentación y el flujo de valor. Hacer BDD es hacer tres cosas una y otra vez: se toma una pequeña funcionalidad y se conversa sobre los detalles de cómo se espera que el sistema se comporte usando ejemplos concretos, luego se documentan esos ejemplos en una forma en la cual se pueden automatizar y se corrobora que hay acuerdo, para terminar se codifica con lenguaje Guerkin el comportamiento descrito en cada ejemplo. A estas tres actividades se las llama: Descubrir, formular y automatizar.

La idea es hacer cada nueva funcionalidad en partes muy pequeñas (ejemplos) e iterar rápidamente. Cada vez que se implementa un ejemplo se añade algo valioso al sistema y se está en disposición de responder a posibles cambios como resultado de la retroalimentación recogida de los expertos en el negocio. Los ejemplos documentados guían el desarrollo y permiten al equipo tener confianza y progresar en la construcción del sistema. A la documentación que se va construyendo se le llama “documentación viva” porque el código representa la documentación y la documentación refleja el conocimiento compartido del equipo sobre lo que el código hace. Cucumber es una herramienta que sirve para hacer BDD y se va a usar a continuación para mostrar un ejemplo de lo explicado hasta aquí.

El ejemplo está basado en el curso online que suministran en Escuela Cucumber de forma gratuita, sólo hay que registrarse. El ejemplo tiene la siguiente estructura.

El contenido de Belly.feature es la codificación del ejemplo en Guerkin. La idea expresada es que si comes menos de 42 galletas y pasa más de una hora vas a estar hambriento y tu estómago va a gruñir, pero si has tomado más de 42 galletas no gruñirá.

La implementación del ejemplo para que la librería de Cucumber pueda ejecutar la prueba escrita en Guerkin en Belly.feature está en StepsBelly.java.

La funcionalidad del negocio está en Belly.java, esta aplicación determina si la barriga(belly) está llena o no después de haber transcurrido una hora y haber consumido una determinada cantidad de galletas.

Resumen

Estos tres ficheros son una pequeña muestra de lo que BDD, Guerkin y Cucumber pueden hacer para mejorar el desarrollo de software.

  • Belly.Feature está escrito en un lenguaje entendible por el usuario y expresa lo que él espera que el sistema haga.
  • StepsBelly.java es la implementación en java de Belly.Feature, cuando se ejecuta valida lo que se espera que haga la aplicación. Hay que tener en cuenta que lo que se espera que haga la aplicación lo ha escrito el experto en el negocio.
  • Belly.java es la aplicación cuya funcionalidad se comprueba automáticamente con StepsBelly.java que se ejecuta con Cucumber.

No hay fisuras posibles entre lo que quiere el experto en el negocio y lo que codifica el desarrollador. Bueno hay que estudiar cómo usar todo esto en el mundo real, pero eso es otra historia…..

viernes, 16 de junio de 2023

JavaScript: Como asegurarse de que es una Shallow copy.

La forma de asegurarnos que estamos haciendo una shallow copy es:

const myShallowCopy = JSON.parse(JSON.stringify(myObj));

con JSON.Stringify se convierte el objeto a copiar en una cadena de caracteres y con JSON.parse se vuelve a convertir en objeto. De esta manera estamos creando un nuevo objeto situado en otra referencia de memoria, es decir una shallow copy.

¿Por qué todo este jaleo? Depende de las necesidades del algoritmo a programar, nos interesa realizar deep copy (copia profunda) o shalow copy(copia superficial). Normalmente nos interesa copia superficial, de esta manera tenemos dos objetos independientes.

Diferencias entre deep y shallow copy.

Shallow copy copia un objeto en otra parte de la memoria (referencia). Entonces disponemos de dos objetos iguales que son independientes.

Deep copy copia la referencia al objeto copiado. Realmente es como si se tienen dos nombres para un mismo objeto, si se cambia algo en uno de ellos cambia automáticamente en el otro. Los dos objetos están apuntando a la misma referencia de memoria.

Ejemplo.

let obj = {a:1};
let shallowObj = {...obj};
shallowObj.a = 2;
console.log ("Shallow copy: obj "+JSON.stringify(obj)+" shallowObj "+ JSON.stringify(shallowObj));
// Shallow copy: obj {"a":1} shallowObj {"a":2}

let deepObj = obj;
deepObj.a = 3;
console.log (" Deep copy: obj "+JSON.stringify(obj)+" deepObj "+ JSON.stringify(deepObj));
// Deep copy: obj {"a":3} deepObj {"a":3}

La imagen muestra el comportamiento de shallow y deep copy. Cuando se modifica la shallow copy el objeto original no cambia, sin embargo sí cambia si se modifica la deep copy.

Otro Ejemplo más complejo.

Cuando un objeto contiene otro objeto en sus propiedades se produce una particularidad.

let obj = {a:1, b: {a:1}};
let shallowObj = {...obj};
shallowObj.a = 2;
shallowObj.b.a = 2;
console.log ("Shallow copy: obj "+JSON.stringify(obj) +" shallowObj "+ JSON.stringify(shallowObj));
// Shallow copy: obj {"a":1,"b":{"a":2}} shallowObj {"a":2,"b":{"a":2}}

obj = {a:1, b: {a:1}};
let deepObj = obj;
deepObj.a = 2;
deepObj.b.a = 2;
console.log (" Deep copy: obj "+JSON.stringify(obj)+" deepObj "+ JSON.stringify(deepObj));
// Deep copy: obj {"a":2,"b":{"a":2}} deepObj {"a":2,"b":{"a":2}}

La particularidad se produce en la Shallow copy, cuando se cambia el valor de la propiedad a del objeto almacenado en la propiedad b, es decir shallowObj1.b.a. Resulta que este objeto se ha copiado por referencia, o sea es una deep copy.

En este caso el problema es que el objeto b que está dentro del shallowObj en vez de copiarse como un nuevo objeto se ha copiado como una referencia al objeto dentro de la propiedad b de obj. Por eso cuando se cambia shallow.b.a resulta que estamos cambiando también obj.b.a.

Solución.

Esto puede ser inesperado para el programador que cuando cambia el valor en la copia también está cambiando el valor en el original. Una solución a esto es utilizar la sentencia mostrada al principio del artículo. Con stringify y parse nos aseguramos de que la shallow copy es total independientemente de los objetos contenidos en propiedades y los posibles anidamientos. Al hacer el parse se crean nuevos objetos, nunca copias por referencia. Por lo tanto los objetos son independientes y se pueden manejar sin interferir los valores de uno en los valores del otro.

Si quieres ver un video en el que explico los ejemplos, lo puedes hacer aqui

viernes, 17 de marzo de 2023

La economía del software según J. B. Rainsberger

Este artículo está basado en una conferencia de 2019 titulada “The economics of software design” de J.B. Rainsberger y que está disponible en Youtube en ver conferencia .

Lo que aquí relato es mi libre interpretación de lo que cuenta Rainsberger, lo digo porque puedo estar equivocada y tergiversar sus palabras. O sea son mis palabras, no las suyas, por si acaso. Es para que no me pase lo mismo que al tipo de la cola del cine en la película “Annie Hall” cuando habla sobre el trabajo de Marshall MacLujan ver escena.

El objetivo de la conferencia es explicar porque son necesarias prácticas ágiles a la hora de desarrollar software. Rainsberger con mucho talento sigue un hilo sólido que explica a desarrolladores y no desarrolladores porqué usar practicas ágiles va a mejorar los sistemas de información.

Rainsberger dice que hay tres asuntos importantes en los que hay que centrar la atención cuando se desarrolla software:

  • Las funcionalidades desarrolladas (Features)
  • El diseño del software (Design)
  • La retroalimentación (Feedback)

Funcionalidades desarrolladas

La refactorización es la piedra angular del desarrollo de código. Esta refactorización facilita mejorar el coste marginal. El coste marginal es un término financiero que se puede definir como el incremento de coste al producir N+1 unidades de determinado producto, respecto al coste de producción de N unidades. Llevando esto al mundo software, se puede traducir en el coste de añadir una nueva funcionalidad o cambiar una funcionalidad ya existente. Es menor de añadir o modificar funcionalidades si el sistema está bien diseñada, es decir no es un galimatías. Los patrocinadores del software (financiero de la empresa u organismo) entienden de costes marginales, los desarrolladores de diseño del software. Entonces, si para tener un mejor coste marginal es necesario refactorizar los promotores entienden que refactorizar es necesario, los desarrolladores ya lo saben. La forma de refactorizar constantemente es utilizar TDD (Test Driven Development).

Diseño del software

Para su exposición Rainsberger utiliza el siguiente gráfico.

Aquí la curva representada por g representa el aumento del coste de seguir modificando un sistema que no se desarrolla con “Diseño Evolutivo”. Inicialmente desarrollar el sistema es menos costoso, pero con el tiempo el coste de mantenerlo se eleva exponencialmente, según Rainsberger siguiendo el comportamiento del interés compuesto según Bernoulli, de hay la formula (1+1/n)ⁿ -> e. Sin embargo la curva representada por f corresponde a los sistemas que se desarrollan con “Diseño Evolutivo” (básicamente empleando TDD), en estos el diseño está mejorando constantemente y eso contribuye a que aunque cada vez el sistema sea más complejo el crecimiento de costes sea mucho más moderado. En términos más vulgares que el galimatías sea menor, aunque la complejidad sea mayor.

También dice Rainsberger que el punto t₀ en el caso de los sistemas que no se desarrollan con "Diseño Evolutivo" es el momento en que económicamente es más rentable tirar el sistema y hacerlo de nuevo. Cómo según él nadie sabe calcular cuando llega ese momento, es mejor trabajar con “diseño evolutivo” para evitar el desastre.

Retroalimentación

En cuanto a la producción del software existe un modelo clásico llamado “En cascada” que implica las fases:

Requisitos -> Análisis-> Diseño-> Codificación -> Pruebas -> Puesta en marcha

En este modelo la retroalimentación se ejecuta demasiado tarde. Esto provoca que la cantidad de re-trabajo suela ser ingente porque cuando algo no se ajusta a lo esperado ya hay mucho que cambiar.

En “XP (eXtreme Programming de 1999)” se expuso que era mejor realizar un ciclo de desarrollo y pruebas constante que pusiera en evidencia si lo que se estaba desarrollando era lo que se necesitaba. XP y a continuación Agile aconsejan prácticas que mejoran la retroalimentación: pequeños ciclos de desarrollo, pruebas unitarias para conocer el estado interno del sistema y pruebas de aceptación para saber si el sistema está de acuerdo con las necesidades del usuario.

Rainsberger expone que las técnicas para llevar esto a cabo son TDD y BDD. También las prácticas de DevOps ayudan a la retroalimentación y facilitan la labor coordinada de los equipos de desarrollo y operaciones.

Conclusiones

Esta conferencia apoya de forma empírica y heurística el desarrollo basado en técnicas ágiles.

No hay fórmulas mágicas, pero desarrollar software no es fácil y yo también estoy convencida de que todas las prácticas ágiles contribuyen a que el mundo del desarrollo de software mejore.

Buenas noticias, eso nos beneficia a todos a los informáticos y a los no informáticos.

lunes, 20 de febrero de 2023

Expresiones regulares en JavaScript

Qué es una expresión regular y como se crea en JavaScript.

Una expresión regular es una secuencia de caracteres que conforma un patrón de búsqueda. Este patrón se utiliza para buscar dentro conjuntos de caracteres contenidos en: literales, variables, ficheros, etc. y comprobar si hay coincidencia o no en la búsqueda.

Las búsquedas con patrones tienen muchas utilidades. Por ejemplo:

  • Buscar una subcadena dentro de una cadena de caracteres.
  • Reemplazar partes de una cadena por otras subcadenas.
  • Validar el formato de un dato.
  • Formatear datos.
  • Filtrar información y extraer datos que cumplan ciertas condiciones.
Las expresiones regulares no son complicadas, pero en una primera aproximación pueden intimidar. Cuando se comprenden y se saben manejar la perspectiva cambia y se convierten en grandes aliados de los programadores.

Un patrón es un objeto RegExp de JavaScript que se crea escribiendo caracteres entre dos barras oblicuas. Luego se puede utilizar de distintas formas, por ejemplo con el método test() que es uno de los métodos del objeto patrón. Un ejemplo:


   let patron = /verde/;
   console.log (patron.test("¡Qué verde era mi valle!")); // true

Este patrón /verde/ busca el conjunto de caracteres verde en la cadena "¡Qué verde era mi valle!" y como hay coincidencia devuelve true.

Hay más métodos de los objetos JavaScript que manejan los patrones. Por ejemplo el método search() del objeto String. Este método devuelve -1 si no encuentra coincidencia y un número positivo que indica la posición donde encuentra el patrón. Por ejemplo:


   "!Qué verde era mi valle¡".search(patr);

devuelve un 5 que es la posición de la cadena donde empieza la palabra verde si se cuenta de izquierda a derecha en la cadena empezando por 0.

Metacaracteres en las expresiones regulares.

En los patrones se usan caracteres que tienen significados especiales y es lo que se llama metacaracteres. Por ejemplo el caracter . en un patrón significa coincidencia con cualquier caracter. Un ejemplo:


   let patr = /r..a/; // Busca una r, 2 caracteres cualesquiera y una a.
   let cadena = "La casa roja";
   console.log (patr.test(cadena)); // true
   cadena = "La casa rosa";
   console.log (patr.test(cadena)); // true
   cadena = "El ron era bueno"; 
   console.log (patr.test(cadena)); // false
   cadena = "El remo se rompió";
   console.log (patr.test(cadena)); // false

Hay muchos metacaracteres para crear expresiones regulares y conseguir con los patrones realizar busquedas complejas. Estos patrones evitan muchas veces tener que crear largos algoritmos de programación. Por ejemplo:


/[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)*@[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)*[.][a-zA-Z]{2,5}/

este patrón sirve para comprobar si una dirección de correo electrónico tiene un formato correcto. De esta forma con esta sola línea se consigue evitar tener que idear y codificar un algoritmo que lo compruebe y cuantas menos líneas de código escritas, menos líneas de código a mantener.

Ejemplo de dos metacaracteres usados normalmente.

Metacaracter.

Significado ➝ Cualquier caracter.

Ejemplo:


   let patr = /a..a./; 
   let cadena = "ambar";
   console.log (patr.test(cadena)); // true
   cadena = "amigo";
   console.log (patr.test(cadena)); // false

Metacaracter\d

Significado ➝ Cualquier caracter que sea un número arábigo, es decir 0, 1 ,2 ,3 ,4 ,5 ,6 , 7 ,8 o 9

Ejemplo:


   let patr = /\d/; 
   let cadena = "Juan tiene 18 años";
   console.log (patr.test(cadena)); // true
   cadena = "Juan tiene dieciocho años";
   console.log (patr.test(cadena)); // false

Si necesitas más información sobre expresiones regulares y más ejemplos puedes consultar el libro Uso de expresiones regulares en JavaScript

O si lo prefieres puedes inscribirte en este curso Expresiones regulares en JavaScript

martes, 10 de enero de 2023

JavaScript: Guia rápida de expresiones regulares

Aquí hay un resumen de los meta-caracteres y otras estructuras más empleados en las expresiones regulares. Si necesitas una explicación mas detallada y ver algunos ejemplos puedes consultar el libro Uso de expresiones regulares en JavaScript


Metacaracteres generales


Metacaracter Significado
\d Cualquier caracter que sea un número arábigo, es decir 0, 1 ,2 ,3 ,4 ,5 ,6 , 7 ,8 o 9
\D Cualquier que no sea un número arábigo, es decir 0, 1, 2, 3, 4, 5, 6, 7, 8 o 9
\w Cualquier caracter del alfabeto latino básico es decir letras minúsculas, letras mayúsculas y guión de subrayado
\W Cualquier caracter que no sea del alfabeto latino básico es decir letras minúsculas, letras mayúsculas, números arábigos y guión de subrayado
\s Encuentra coincidencia cuando hay un espacio u otros caracteres no imprimibles
\^ Comprueba el principio de la cadena
\$ Comprueba el final de la cadena
\ Indica que el siguiente caracter, tiene que ser tratado de forma especial. Es útil para tratar meta-caracteres como caracteres especiales y para tratar caracteres normales como meta-caracteres
\b Comprueba límites de palabra. Un límite de palabra es la posición donde un caracter de palabra no es seguido o precedido por otro caracter de palabra. Los caracteres de palabra son: letras del alfabeto latino en mayúsculas o minúsculas, números arábigos o sea los caracteres del 0 al 9 y el caracter de subrayado
\B Comprueba límites de no palabra. Un límite de no palabra es la posición donde un caracter de palabra es seguido o precedido por otro caracter de palabra. Los caracteres de palabra son: letras del alfabeto latino en mayúsculas o minúsculas, números arábigos o sea los caracteres del 0 al 9 y el caracter de subrayado. Es decir busca que un caracter esté seguido o precedido por otro del mismo tipo, de palabra o de no palabra
[abc] o [a-c] Encuentra coincidencia si hay alguno de los caracteres que aparecen entre corchetes en la cadena. También se pueden especificar rangos de caracteres mediante un guión, así [abc] es lo mismo que [a-c]
[^abc] o [^a-c] Encuentra coincidencia si encuentra algún caracter distinto de los que aparecen entre corchetes en la cadena. También se pueden especificar rangos de caracteres mediante un guión, así [^abc] es lo mismo que [^a-c]
\t Hay coincidencia si encuentra un tabulador horizontal en la cadena. Hay que tener en cuenta que este caracter es un Non Printable Character y los editores normalmente no lo muestran como tal sino que lo interpretan como una orden, en este caso que el caracter siguiente se muestre más a la derecha
\r \n \v \f Estos al igual que el anterior son Non Printable Characteres y los editores normalmente no lo muestran como tal sino que lo interpretan como una orden. Cada uno tiene un significado distinto: \r carriage return (junto a \n salto de línea), \n linefeed (salto de línea), \v vertical tab y \f form-feed (salto de página)
x|y Disyunción: coincide si hay x o y. Cada componente separado por | se llama alternativa

Metacaracteres cuantificadores


Metacaracter Significado
x* El item precedente 'x' se repite 0 o más veces
x+ El item precedente 'x' se repite 1 o más veces
x? El item precedente 'x' se repite 0 o 1 vez
x{n} El item precedente 'x' se repite exactamente n veces

Grupos


Grupo Significado
(abc) Busca la cadena abc
(/w/w) Busca 2 caracteres del alfabeto latino seguidos
(?<g>abc) El grupo se llama g. Luego se puede usar con \k<g>
(([0-9]){2}-){3} Los grupos se pueden anidar. En este caso el primer grupo es un numero que se tiene que repetir 2 veces seguido de un guión es el segundo grupo que anida al primero. Luego todo eso se repite 3 veces

Flags


Flag Significado
i Encuentra coincidencia sin distinguir mayúsculas de minúsculas
g Encuentra todas las coincidencias del patrón en la cadena
m Significa busqueda multilínea. Solo es aplicable a los metacarateres ^ y $ de principio y final de línea
s Es aplicable al metacaracter .. Cuando se usa el flag s el . encuentra coincidencia con salto de línea \n
u JavaScript utiliza la codificación Unicode, esto determina como se almacenan internamente los caracteres en memoria. Existen caracteres que se guardan de 2 bytes (16 bits de 0s y 1s) y otros que se guardan en 4 bytes. Hay que tener en cuenta que Unicode tiene combinaciones de 0s y 1s para representar los caracteres de cualquier idioma, una a sería 01000001 en binario o 41 en hexadecimal.
Para construir patrones para Unicode se usa el metacaracter \p junto con otros caracteres que se ponen entre {}, por ejemplo {Sc} significa symbol y currency (símbolo y moneda)
y Busca el patrón en una posición determinada dentro de la cadena. Para establecer la posición en la que buscar se usar la propiedad lastIndex de RegExp

Objetos para manejar patrones


Objeto.Método Uso
RegExp.text() El método test() ejecuta una busqueda del patrón dentro de una cadena de caracteres (string), devolviendo true si lo encuentra o false sino lo encuentra
RegExp.exec() El método exec() realiza una búsqueda para encontrar el patrón dentro de una cadena de caracteres (string) y devuelve un array con los resultados. Sino hay coincidencias devuelve null
String.match() Con la bandera g de global, este método devuelve un array con las coincidencias encontradas
String.matchAll() Debe llevar la bandera g y devuelve un iterador que contiene las coincidencias del patrón encontradas en la cadena
String.split() Separa la cadena por el patrón especificado y crea un array con las subcadenas obtenidas
String.search() Busca la primera coincidencia del patrón y devuelve la posición dentro de la cadena en la que lo encuentra
String.replace() Reemplaza una cadena o las coincidencias del patrón con la cadena especificada. El método replace tiene dos argumentos, uno para especificar la cadena o patrón a reemplazar y el segundo para especificar conqué hay que reemplazarlo