Expresión regular - Regular expression

Los resultados de coincidencia del patrón
(?<=\.) {2,}(?=[A-Z])
Se hacen coincidir al menos dos espacios, pero solo si aparecen directamente después de un punto (.) Y antes de una letra mayúscula.
Stephen Cole Kleene , quien introdujo el concepto
Una lista negra en Wikipedia que utiliza expresiones regulares para identificar títulos incorrectos.

Una expresión regular (abreviada como regex o regexp ; también conocida como expresión racional ) es una secuencia de caracteres que especifica un patrón de búsqueda . Por lo general, estos patrones son utilizados por algoritmos de búsqueda de cadenas para operaciones de "buscar" o "buscar y reemplazar" en cadenas , o para la validación de entrada. Es una técnica desarrollada en informática teórica y teoría del lenguaje formal .

El concepto de expresiones regulares comenzó en la década de 1950, cuando el matemático estadounidense Stephen Cole Kleene formalizó la descripción de un lenguaje regular . Llegaron a ser de uso común con las utilidades de procesamiento de texto de Unix . Desde la década de 1980 han existido diferentes sintaxis para escribir expresiones regulares, una es el estándar POSIX y otra, ampliamente utilizada, es la sintaxis Perl .

Las expresiones regulares se utilizan en motores de búsqueda , buscar y reemplazar diálogos de procesadores de texto y editores de texto , en utilidades de procesamiento de texto como sed y AWK y en análisis léxico . Muchos lenguajes de programación proporcionan capacidades de expresiones regulares integradas o mediante bibliotecas , ya que tiene usos en muchas situaciones.

Historia

Las expresiones regulares se originaron en 1951, cuando el matemático Stephen Cole Kleene describió los lenguajes regulares usando su notación matemática llamada eventos regulares . Estos surgieron en la informática teórica , en los subcampos de la teoría de autómatas (modelos de computación) y la descripción y clasificación de lenguajes formales . Otras implementaciones tempranas de coincidencia de patrones incluyen el lenguaje SNOBOL , que no utiliza expresiones regulares, sino sus propias construcciones de coincidencia de patrones.

Las expresiones regulares entraron en uso popular a partir de 1968 en dos usos: coincidencia de patrones en un editor de texto y análisis léxico en un compilador. Entre las primeras apariciones de expresiones regulares en forma de programa fue cuando Ken Thompson incorporó la notación de Kleene en el editor QED como un medio para hacer coincidir patrones en archivos de texto . Para mayor velocidad, Thompson implementó la comparación de expresiones regulares mediante la compilación Just -In-Time (JIT) con el código IBM 7094 en el Compatible Time-Sharing System , un importante ejemplo temprano de compilación JIT. Más tarde agregó esta capacidad al editor de Unix ed , lo que eventualmente llevó al uso de expresiones regulares de la popular herramienta de búsqueda grep ("grep" es una palabra derivada del comando para la búsqueda de expresiones regulares en el editor ed: que significa "Búsqueda global para líneas de coincidencia de expresión regular e impresión "). Casi al mismo tiempo que Thompson desarrolló QED, un grupo de investigadores, incluido Douglas T. Ross, implementó una herramienta basada en expresiones regulares que se utiliza para el análisis léxico en el diseño de compiladores . g/re/p

Muchas variaciones de estas formas originales de expresiones regulares se usaron en programas Unix en Bell Labs en la década de 1970, incluidos vi , lex , sed , AWK y expr , y en otros programas como Emacs . Las expresiones regulares fueron posteriormente adoptadas por una amplia gama de programas, con estas primeras formas estandarizadas en el estándar POSIX.2 en 1992.

En la década de 1980, las expresiones regulares más complicadas surgieron en Perl , que originalmente se derivaba de una biblioteca de expresiones regulares escrita por Henry Spencer (1986), quien más tarde escribió una implementación de Expresiones regulares avanzadas para Tcl . La biblioteca Tcl es una implementación híbrida de NFA / DFA con características de rendimiento mejoradas. Los proyectos de software que han adoptado la implementación de expresiones regulares Tcl de Spencer incluyen PostgreSQL . Perl luego amplió la biblioteca original de Spencer para agregar muchas características nuevas. Parte del esfuerzo en el diseño de Raku (anteriormente llamado Perl 6) es mejorar la integración de expresiones regulares de Perl y aumentar su alcance y capacidades para permitir la definición de análisis de gramáticas de expresión . El resultado es un mini lenguaje llamado reglas de Raku , que se utilizan para definir la gramática de Raku y proporcionar una herramienta a los programadores en el lenguaje. Estas reglas mantienen las características existentes de las expresiones regulares de Perl 5.x, pero también permiten la definición al estilo BNF de un analizador de descendencia recursivo a través de subreglas.

El uso de expresiones regulares en los estándares de información estructurada para el modelado de documentos y bases de datos comenzó en la década de 1960 y se expandió en la década de 1980 cuando se consolidaron estándares de la industria como ISO SGML (precursorado por ANSI "GCA 101-1983"). El núcleo de los estándares del lenguaje de especificación de estructura consiste en expresiones regulares. Su uso es evidente en la sintaxis del grupo de elementos DTD .

A partir de 1997, Philip Hazel desarrolló PCRE (Expresiones regulares compatibles con Perl), que intenta imitar de cerca la funcionalidad de expresiones regulares de Perl y es utilizado por muchas herramientas modernas, incluyendo PHP y Apache HTTP Server .

Hoy en día, las expresiones regulares son ampliamente compatibles con lenguajes de programación, programas de procesamiento de texto (en particular, lexers ), editores de texto avanzados y algunos otros programas. El soporte Regex es parte de la biblioteca estándar de muchos lenguajes de programación, incluidos Java y Python , y está integrado en la sintaxis de otros, incluidos Perl y ECMAScript . Las implementaciones de la funcionalidad de expresiones regulares a menudo se denominan motor de expresiones regulares y hay varias bibliotecas disponibles para su reutilización. A finales de la década de 2010, varias empresas comenzaron a ofrecer hardware, FPGA , implementaciones de GPU de motores de expresiones regulares compatibles con PCRE que son más rápidos en comparación con las implementaciones de CPU .

Patrones

La frase expresiones regulares , o regexes , se usa a menudo para referirse a la sintaxis textual estándar específica para representar patrones para texto coincidente, a diferencia de la notación matemática que se describe a continuación. Cada carácter de una expresión regular (es decir, cada carácter de la cadena que describe su patrón) es un metacarácter que tiene un significado especial o un carácter regular que tiene un significado literal. Por ejemplo, en la expresión regular b., 'b' es un carácter literal que coincide solo con 'b', mientras que '.' es un metacarácter que coincide con todos los caracteres excepto con una nueva línea. Por lo tanto, esta expresión regular coincide, por ejemplo, con 'b%', o 'bx' o 'b5'. Juntos, los metacaracteres y los caracteres literales se pueden usar para identificar el texto de un patrón dado o procesar varias instancias de él. Las coincidencias de patrones pueden variar desde una igualdad precisa hasta una similitud muy general, controlada por los metacaracteres. Por ejemplo, .es un patrón muy general [a-z](coincide con todas las letras minúsculas de la 'a' a la 'z') es menos general y bes un patrón preciso (solo coincide con la 'b'). La sintaxis de metacaracteres está diseñada específicamente para representar objetivos prescritos de una manera concisa y flexible para dirigir la automatización del procesamiento de texto de una variedad de datos de entrada, en una forma fácil de escribir usando un teclado ASCII estándar .

Un caso muy simple de una expresión regular en esta sintaxis es ubicar una palabra escrita de dos maneras diferentes en un editor de texto , la expresión regular seriali[sz]ecoincide con "serializar" y "serializar". Los caracteres comodín también logran esto, pero son más limitados en lo que pueden modelar, ya que tienen menos metacaracteres y una base de lenguaje simple.

El contexto habitual de los caracteres comodín consiste en englobar nombres similares en una lista de archivos, mientras que las expresiones regulares se emplean generalmente en aplicaciones que coinciden con patrones de cadenas de texto en general. Por ejemplo, la expresión regular coincide con el exceso de espacios en blanco al principio o al final de una línea. Una expresión regular avanzada que coincide con cualquier número es . ^[ \t]+|[ \t]+$[+-]?(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?

Traducir la estrella de Kleene
( s * significa "cero o más de s ")

Un procesador de expresiones regulares traduce una expresión regular en la sintaxis anterior en una representación interna que se puede ejecutar y comparar con una cadena que representa el texto que se busca. Un enfoque posible es el algoritmo de construcción de Thompson para construir un autómata finito no determinista (NFA), que luego se convierte en determinista y el autómata finito determinista (DFA) resultante se ejecuta en la cadena de texto de destino para reconocer las subcadenas que coinciden con la expresión regular. La imagen muestra el esquema NFA obtenido de la expresión regular , donde s denota una expresión regular más simple a su vez, que ya se ha traducido recursivamente a NFA N ( s ). N(s*)s*

Conceptos básicos

Una expresión regular, a menudo llamada patrón , especifica un conjunto de cadenas necesarias para un propósito particular. Una forma sencilla de especificar un conjunto finito de cadenas es enumerar sus elementos o miembros. Sin embargo, a menudo hay formas más concisas: por ejemplo, el conjunto que contiene las tres cadenas "Handel", "Händel" y "Haendel" se puede especificar mediante el patrón H(ä|ae?)ndel; decimos que este patrón coincide con cada una de las tres cadenas. En la mayoría de los formalismos , si existe al menos una expresión regular que coincide con un conjunto en particular, entonces existe un número infinito de otras expresiones regulares que también lo hacen; la especificación no es única. La mayoría de los formalismos proporcionan las siguientes operaciones para construir expresiones regulares.

Booleano "o"
Una barra vertical separa las alternativas. Por ejemplo, puede coincidir con "gris" o "gris".gray|grey
Agrupamiento
Los paréntesis se utilizan para definir el alcance y la precedencia de los operadores (entre otros usos). Por ejemplo, gray|greyy son patrones equivalentes que describen el conjunto de "gris" o "gris".gr(a|e)y
Cuantificación
Un cuantificador después de un token (como un carácter) o grupo especifica la frecuencia con la que se permite que ocurra un elemento anterior. Los cuantificadores más comunes son el signo de interrogación ? , el asterisco * (derivado de la estrella de Kleene ) y el signo más + ( Kleene plus ).
? El signo de interrogación indica cero o una apariciones del elemento anterior. Por ejemplo, colou?rcoincide con "color" y "color".
* El asterisco indica cero o más ocurrencias del elemento anterior. Por ejemplo, ab*ccoincide con "ac", "abc", "abbc", "abbbc", etc.
+ El signo más indica una o más ocurrencias del elemento anterior. Por ejemplo, ab+ccoincide con "abc", "abbc", "abbbc", etc., pero no con "ac".
{n} El elemento anterior coincide exactamente n veces.
{min,} El elemento anterior se hace coincidir un mínimo de veces.
{,max} El elemento anterior se compara con tiempos máximos .
{min,max} El elemento precedente concuerda al menos min veces, pero no más de max veces.
Comodín

El comodín .coincide con cualquier carácter. Por ejemplo, a.bcoincide con cualquier cadena que contenga una "a", luego con cualquier otro carácter y luego con "b", a.*bcoincide con cualquier cadena que contenga una "a", y luego con el carácter "b" en algún punto posterior.

Estas construcciones se pueden combinar para formar expresiones arbitrariamente complejas, al igual que se pueden construir expresiones aritméticas a partir de números y las operaciones +, -, × y ÷. Por ejemplo, H(ae?|ä)ndely son los dos patrones válidos que se ajustan a las mismas cadenas que el ejemplo anterior, . H(a|ae|ä)ndelH(ä|ae?)ndel

La sintaxis precisa de las expresiones regulares varía entre las herramientas y el contexto; se dan más detalles en § Sintaxis .

Teoría del lenguaje formal

Las expresiones regulares describen lenguajes regulares en la teoría del lenguaje formal . Tienen el mismo poder expresivo que las gramáticas regulares .

Definicion formal

Las expresiones regulares constan de constantes, que denotan conjuntos de cadenas y símbolos de operador, que denotan operaciones sobre estos conjuntos. La siguiente definición es estándar y se encuentra como tal en la mayoría de los libros de texto sobre teoría del lenguaje formal. Dado un alfabeto finito Σ, las siguientes constantes se definen como expresiones regulares:

  • ( conjunto vacío ) ∅ que denota el conjunto ∅.
  • ( cadena vacía ) ε indica el conjunto que contiene solo la cadena "vacía", que no tiene ningún carácter.
  • ( carácter literal ) aen Σ que denota el conjunto que contiene solo el carácter a .

Dadas las expresiones regulares R y S, las siguientes operaciones sobre ellas se definen para producir expresiones regulares:

  • ( concatenación ) (RS)denota el conjunto de cadenas que se pueden obtener concatenando una cadena aceptada por R y una cadena aceptada por S (en ese orden). Por ejemplo, deje que R denote {"ab", "c"} y S denote {"d", "ef"}. Luego, (RS)denota {"abd", "abef", "cd", "cef"}.
  • ( alternancia ) (R|S)denota la unión de conjuntos de conjuntos descritos por R y S. Por ejemplo, si R describe {"ab", "c"} y S describe {"ab", "d", "ef"}, la expresión (R|S)describe { "a B C D e F"}.
  • ( Estrella de Kleene ) (R*)denota el superconjunto más pequeño del conjunto descrito por R que contiene ε y está cerrado bajo concatenación de cadenas. Este es el conjunto de todas las cadenas que se pueden hacer concatenando cualquier número finito (incluido el cero) de cadenas del conjunto descrito por R. Por ejemplo, si R denota {"0", "1"}, (R*)denota el conjunto de todos cadenas binarias finitas (incluida la cadena vacía). Si R denota {"ab", "c"}, (R*)denota {ε, "ab", "c", "abab", "abc", "cab", "cc", "ababab", "abcab",. ..}.

Para evitar los paréntesis, se supone que la estrella de Kleene tiene la prioridad más alta, luego la concatenación y luego la alternancia. Si no hay ambigüedad, se pueden omitir los paréntesis. Por ejemplo, (ab)cse puede escribir como abcy a|(b(c*))se puede escribir como a|bc*. Muchos libros de texto usan los símbolos ∪, + o ∨ para alternar en lugar de la barra vertical.

Ejemplos:

  • a|b* denota {ε, "a", "b", "bb", "bbb", ...}
  • (a|b)* denota el conjunto de todas las cadenas sin símbolos más que "a" y "b", incluida la cadena vacía: {ε, "a", "b", "aa", "ab", "ba", "bb" , "aaa", ...}
  • ab*(c|ε) denota el conjunto de cadenas que comienzan con "a", luego cero o más "b" sy finalmente opcionalmente una "c": {"a", "ac", "ab", "abc", "abb", "abbc ", ...}
  • (0|(1(01*0)*1))* denota el conjunto de números binarios que son múltiplos de 3: {ε, "0", "00", "11", "000", "011", "110", "0000", "0011", "0110" , "1001", "1100", "1111", "00000", ...}

Poder expresivo y compacidad

La definición formal de las expresiones regulares es mínima a propósito y evita definir ?y; +estas se pueden expresar de la siguiente manera: a+= aa*, y a?= (a|ε). A veces se agrega el operador de complemento para dar una expresión regular generalizada ; aquí R c coincide con todas las cadenas sobre Σ * que no coinciden con R . En principio, el operador del complemento es redundante, porque no otorga más poder expresivo. Sin embargo, puede hacer que una expresión regular sea mucho más concisa: la eliminación de un operador de complemento simple puede provocar una expansión exponencial doble de su longitud.

Las expresiones regulares en este sentido pueden expresar los lenguajes regulares, exactamente la clase de lenguajes aceptados por los autómatas finitos deterministas . Sin embargo, existe una diferencia significativa en la compacidad. Algunas clases de lenguajes regulares solo pueden describirse mediante autómatas finitos deterministas cuyo tamaño crece exponencialmente en el tamaño de las expresiones regulares equivalentes más cortas. El ejemplo estándar aquí son los idiomas L k que constan de todas las cadenas sobre el alfabeto { a , b } cuya k th -desde-la-última letra es igual  a a . Por un lado, una expresión regular que describe L 4 viene dada por .

Generalizar este patrón a L k da la expresión:

Por otro lado, se sabe que todo autómata finito determinista que acepta el lenguaje L k debe tener al menos 2 k estados. Afortunadamente, existe un mapeo simple de expresiones regulares a los autómatas finitos no deterministas (NFA) más generales que no conduce a tal aumento de tamaño; por esta razón, las NFA se utilizan a menudo como representaciones alternativas de los lenguajes regulares. Los NFA son una variación simple de las gramáticas de tipo 3 de la jerarquía de Chomsky .

En la dirección opuesta, hay muchos lenguajes que un DFA describe fácilmente y que no se describen fácilmente como una expresión regular. Por ejemplo, determinar la validez de un ISBN dado requiere calcular el módulo de la base entera 11 y se puede implementar fácilmente con un DFA de 11 estados. Sin embargo, una expresión regular para responder al mismo problema de divisibilidad por 11 tiene al menos varios megabytes de longitud.

Dada una expresión regular, el algoritmo de construcción de Thompson calcula un autómata finito no determinista equivalente. El algoritmo de Kleene logra una conversión en la dirección opuesta .

Finalmente, vale la pena señalar que muchos motores de "expresiones regulares" del mundo real implementan características que no pueden ser descritas por las expresiones regulares en el sentido de la teoría del lenguaje formal; más bien, implementan expresiones regulares . Consulte a continuación para obtener más información sobre esto.

Decidir la equivalencia de expresiones regulares

Como se ve en muchos de los ejemplos anteriores, hay más de una forma de construir una expresión regular para lograr los mismos resultados.

Es posible escribir un algoritmo que, para dos expresiones regulares dadas, decida si los lenguajes descritos son iguales; el algoritmo reduce cada expresión a una máquina de estados finitos determinista mínima y determina si son isomórficas (equivalentes).

Las leyes algebraicas para expresiones regulares se pueden obtener usando un método de Gischer que se explica mejor con un ejemplo: para verificar si ( X + Y ) * y ( X * Y * ) * denotan el mismo lenguaje regular, para todas las expresiones regulares X , Y , es necesario y suficiente comprobar si las expresiones regulares particulares ( a + b ) * y ( a * b * ) * denotan el mismo idioma sobre el alfabeto Σ = { a , b }. De manera más general, una ecuación E = F entre términos de expresión regular con variables se cumple si, y solo si, se cumple su instanciación con diferentes variables reemplazadas por diferentes constantes de símbolo.

La redundancia se puede eliminar usando Kleene star y set union para encontrar un subconjunto interesante de expresiones regulares que aún sea completamente expresivo, pero tal vez su uso pueda restringirse. Este es un problema sorprendentemente difícil. Tan simples como son las expresiones regulares, no existe un método para reescribirlas sistemáticamente a alguna forma normal. La falta de axioma en el pasado llevó al problema de la altura de las estrellas . En 1991, Dexter Kozen axiomatizó las expresiones regulares como un álgebra de Kleene , utilizando axiomas de ecuaciones y cláusulas de Horn . Ya en 1964, Redko había demostrado que ningún conjunto finito de axiomas puramente ecuacionales puede caracterizar el álgebra de los lenguajes regulares.

Sintaxis

Un patrón de expresiones regulares coincide con una cadena de destino . El patrón está compuesto por una secuencia de átomos . Un átomo es un único punto dentro del patrón de expresiones regulares que intenta hacer coincidir con la cadena de destino. El átomo más simple es un literal, pero agrupar partes del patrón para que coincidan con un átomo requerirá su uso ( )como metacaracteres. Los metacaracteres ayudan a formar: átomos ; cuantificadores que dicen cuántos átomos (y si es un cuantificador codicioso o no); un carácter OR lógico, que ofrece un conjunto de alternativas, y un carácter NOT lógico, que niega la existencia de un átomo; y backreferences para referirse a átomos anteriores de un patrón completo de átomos. Se hace una coincidencia, no cuando todos los átomos de la cadena coinciden, sino cuando todos los átomos del patrón en la expresión regular coinciden. La idea es hacer que un pequeño patrón de caracteres represente una gran cantidad de cadenas posibles, en lugar de compilar una gran lista de todas las posibilidades literales.

Dependiendo del procesador de expresiones regulares, hay alrededor de catorce metacaracteres, caracteres que pueden tener o no su significado de carácter literal , dependiendo del contexto, o si están "escapados", es decir, precedidos por una secuencia de escape , en este caso, la barra invertida \. Las expresiones regulares modernas y POSIX extendidas usan metacaracteres con más frecuencia que su significado literal, por lo que para evitar la "barra invertida-osis" o el síndrome del palillo de dientes inclinado , tiene sentido que un metacarácter escape a un modo literal; pero para empezar, tiene más sentido tener los cuatro metacaracteres entre corchetes ( )y { }ser principalmente literal, y "escapar" de este significado habitual para convertirse en metacaracteres. Los estándares comunes implementan ambos. Los metacaracteres habituales son {}[]()^$.|*+?y \. Los personajes habituales que se convierten en metacaracteres cuando se escapan son dswDSWy N.

Delimitadores

Cuando se ingresa una expresión regular en un lenguaje de programación, se pueden representar como un literal de cadena habitual, por lo que se suelen citar; esto es común en C, Java y Python, por ejemplo, donde la expresión regular rese ingresa como "re". Sin embargo, a menudo se escriben con barras inclinadas como delimitadores , como en el /re/caso de la expresión regular re. Esto se origina en ed , donde /es el comando del editor para la búsqueda, y /re/se puede usar una expresión para especificar un rango de líneas (que coincidan con el patrón), que se pueden combinar con otros comandos en cualquier lado, el más famoso g/re/pes grep ("global regex print "), que se incluye en la mayoría de los sistemas operativos basados en Unix , como las distribuciones de Linux . Se usa una convención similar en sed , donde la búsqueda y el reemplazo vienen dados por s/re/replacement/y los patrones se pueden unir con una coma para especificar un rango de líneas como en /re1/,/re2/. Esta notación es particularmente conocida debido a su uso en Perl , donde forma parte de la sintaxis distinta de los literales de cadena normales. En algunos casos, como sed y Perl, se pueden utilizar delimitadores alternativos para evitar la colisión con el contenido y evitar tener que escapar de las apariciones del carácter delimitador en el contenido. Por ejemplo, en sed, el comando s,/,X,reemplazará a /por an X, usando comas como delimitadores.

Estándares

El estándar IEEE POSIX tiene tres conjuntos de cumplimiento: BRE (Expresiones regulares básicas), ERE (Expresiones regulares extendidas) y SRE (Expresiones regulares simples). SRE está en desuso , a favor de BRE, ya que ambos proporcionan compatibilidad con versiones anteriores . La subsección a continuación que cubre las clases de personajes se aplica tanto a BRE como a ERE.

BRE y ERE trabajan juntos. ERE se suma ?, +y |, y elimina la necesidad de escapar de los metacaracteres ( )y { }que se requerían en BRE. Además, siempre que se adhiera a la sintaxis estándar POSIX para expresiones regulares, puede haber, y a menudo hay, sintaxis adicional para servir aplicaciones específicas (pero compatibles con POSIX). Aunque POSIX.2 deja algunos detalles de implementación sin definir, BRE y ERE proporcionan un "estándar" que desde entonces ha sido adoptado como la sintaxis predeterminada de muchas herramientas, donde la elección de los modos BRE o ERE suele ser una opción admitida. Por ejemplo, GNU grep tiene las siguientes opciones: " grep -E" para ERE, y " grep -G" para BRE (el predeterminado) y " grep -P" para expresiones regulares de Perl .

Las expresiones regulares de Perl se han convertido en un estándar de facto, con un conjunto rico y poderoso de expresiones atómicas. Perl no tiene niveles "básicos" o "extendidos". Como en POSIX ERE, ( )y { }se tratan como metacaracteres a menos que se escapen; Se sabe que otros metacaracteres son literales o simbólicos basándose únicamente en el contexto. La funcionalidad adicional incluye coincidencias diferidas , referencias inversas , grupos de captura con nombre y patrones recursivos .

POSIX básico y extendido

En el estándar POSIX , la sintaxis regular básica ( BRE ) requiere que los metacaracteres ( ) y { }sean designados \(\)y \{\}, mientras que la sintaxis regular extendida ( ERE ) no lo hace.

Metacarácter Descripción
^ Coincide con la posición inicial dentro de la cuerda. En las herramientas basadas en líneas, coincide con la posición inicial de cualquier línea.
. Coincide con cualquier carácter individual (muchas aplicaciones excluyen las nuevas líneas , y exactamente qué caracteres se consideran nuevas líneas es específico del tipo, la codificación de caracteres y la plataforma, pero es seguro asumir que se incluye el carácter de salto de línea). Dentro de las expresiones de corchetes POSIX, el carácter de punto coincide con un punto literal. Por ejemplo, a.ccoincide con "abc", etc., pero [a.c]solo coincide con "a", "." O "c".
[ ] Una expresión de corchetes. Coincide con un solo carácter contenido entre corchetes. Por ejemplo, [abc]coincide con "a", "b" o "c". [a-z]especifica un rango que coincide con cualquier letra minúscula de "a" a "z". Estas formas se pueden mezclar: [abcx-z]coincide con "a", "b", "c", "x", "y" o "z", como lo hace [a-cx-z].

El -carácter se trata como un carácter literal si es el último o el primer carácter (después del ^, si está presente) entre corchetes: [abc-], [-abc]. Tenga en cuenta que no se permiten los escapes de barra invertida. El ]personaje puede ser incluido en una expresión entre corchetes si es la primera vez (después de la ^) carácter: []abc].

[^ ] Coincide con un solo carácter que no está contenido entre corchetes. Por ejemplo, [^abc]coincide con cualquier carácter que no sea "a", "b" o "c". [^a-z]coincide con cualquier carácter que no sea una letra minúscula de la "a" a la "z". Asimismo, se pueden mezclar caracteres y rangos literales.
$ Coincide con la posición final de la cadena o la posición justo antes de una nueva línea al final de la cadena. En las herramientas basadas en líneas, coincide con la posición final de cualquier línea.
( ) Define una subexpresión marcada. La cadena que coincide entre paréntesis se puede recuperar más tarde (consulte la siguiente entrada ). Una subexpresión marcada también se denomina bloque o grupo de captura. El modo BRE requiere . \n\( \)
\n Partidos lo que el n º subexpresión marcado emparejado, donde n es un dígito de 1 a 9. Esta construcción se vagamente definido en el estándar POSIX.2. Algunas herramientas permiten hacer referencia a más de nueve grupos de captura. También conocido como referencia inversa.
* Coincide con el elemento anterior cero o más veces. Por ejemplo, ab*ccoincide con "ac", "abc", "abbbc", etc. [xyz]*coincide con "", "x", "y", "z", "zx", "zyx", "xyzzy", etc. (ab)*coincide con "", "ab", "abab", "ababab", etc.
{m,n} Coincide con el elemento anterior al menos my no más de n veces. Por ejemplo, a{3,5}solo coincide con "aaa", "aaaa" y "aaaaa". Esto no se encuentra en algunas instancias más antiguas de expresiones regulares. El modo BRE requiere\{m,n\} .

Ejemplos:

  • .at coincide con cualquier cadena de tres caracteres que termine en "en", incluidos "sombrero", "gato" y "murciélago".
  • [hc]at coincide con "sombrero" y "gato".
  • [^b]atcoincide con todas las cadenas que coinciden con .atexcepto "bat".
  • [^hc]atcoincide con todas las cadenas de caracteres que .atno sean "sombrero" y "gato".
  • ^[hc]at coincide con "sombrero" y "gato", pero solo al principio de la cadena o línea.
  • [hc]at$ coincide con "sombrero" y "gato", pero solo al final de la cadena o línea.
  • \[.\] coincide con cualquier carácter individual rodeado por "[" y "]" ya que los corchetes son de escape, por ejemplo: "[a]" y "[b]".
  • s.* coincide con la s seguida de cero o más caracteres, por ejemplo: "s" y "sierra" y "semilla".

POSIX extendido

El significado de los metacaracteres escapados con una barra invertida se invierte para algunos caracteres en la sintaxis POSIX Extended Regular Expression ( ERE ). Con esta sintaxis, una barra invertida hace que el metacarácter sea tratado como un carácter literal. Entonces, por ejemplo, \( \)es ahora ( )y \{ \}es ahora { }. Además, se elimina el soporte para referencias inversas y se agregan los siguientes metacaracteres: \n

Metacarácter Descripción
? Coincide con el elemento anterior cero o una vez. Por ejemplo, ab?csolo coincide con "ac" o "abc".
+ Coincide con el elemento anterior una o más veces. Por ejemplo, ab+ccoincide con "abc", "abbc", "abbbc", etc., pero no con "ac".
| El operador de elección (también conocido como alternancia o unión de conjuntos) coincide con la expresión anterior o posterior al operador. Por ejemplo, abc|defcoincide con "abc" o "def".

Ejemplos:

  • [hc]?at coincide con "en", "sombrero" y "gato".
  • [hc]*at coincide con "at", "hat", "cat", "hhat", "chat", "hcat", "cchchat", etc.
  • [hc]+at coincide con "sombrero", "gato", "hhat", "chat", "hcat", "cchchat", etc., pero no "at".
  • cat|dog coincide con "gato" o "perro".

Las expresiones regulares extendidas POSIX a menudo se pueden usar con las utilidades modernas de Unix al incluir el indicador de línea de comando -E .

Clases de personajes

La clase de carácter es el concepto de expresión regular más básico después de una coincidencia literal. Hace que una pequeña secuencia de caracteres coincida con un conjunto más grande de caracteres. Por ejemplo, podría representar cualquier letra mayúscula del alfabeto inglés y podría significar cualquier dígito. Las clases de personajes se aplican a ambos niveles POSIX. [A-Z]\d

Al especificar un rango de caracteres, como (es decir, de minúsculas a mayúsculas ), la configuración regional de la computadora determina el contenido por el orden numérico de la codificación de caracteres. Podrían almacenar dígitos en esa secuencia, o el orden podría ser abc… zABC… Z , o aAbBcC… zZ . Entonces, el estándar POSIX define una clase de carácter, que será conocida por el procesador de expresiones regulares instalado. Esas definiciones se encuentran en la siguiente tabla: [a-Z]aZ

POSIX No estándar Perl / Tcl Empuje Java ASCII Descripción
[:ascii:] \p{ASCII} [\x00-\x7F] Caracteres ASCII
[:alnum:] \p{Alnum} [A-Za-z0-9] Caracteres alfanuméricos
[:word:] \w \w \w [A-Za-z0-9_] Caracteres alfanuméricos más "_"
\W \W \W [^A-Za-z0-9_] Caracteres que no son palabras
[:alpha:] \a \p{Alpha} [A-Za-z] Caracteres alfabéticos
[:blank:] \s \p{Blank} [ \t] Espacio y tabulación
\b \< \> \b (?<=\W)(?=\w)|(?<=\w)(?=\W) Límites de palabras
\B (?<=\W)(?=\W)|(?<=\w)(?=\w) Límites sin palabras
[:cntrl:] \p{Cntrl} [\x00-\x1F\x7F] Personajes de control
[:digit:] \d \d \p{Digit} o \d [0-9] Dígitos
\D \D \D [^0-9] Sin dígitos
[:graph:] \p{Graph} [\x21-\x7E] Caracteres visibles
[:lower:] \l \p{Lower} [a-z] Letras minusculas
[:print:] \p \p{Print} [\x20-\x7E] Caracteres visibles y el carácter de espacio
[:punct:] \p{Punct} [][!"#$%&'()*+,./:;<=>?@\^_`{|}~-] Caracteres de puntuación
[:space:] \s \_s \p{Space} o \s [ \t\r\n\v\f] Caracteres de espacio en blanco
\S \S \S [^ \t\r\n\v\f] Caracteres sin espacios en blanco
[:upper:] \u \p{Upper} [A-Z] Letras mayúsculas
[:xdigit:] \x \p{XDigit} [A-Fa-f0-9] Dígitos hexadecimales

Las clases de caracteres POSIX solo se pueden usar dentro de expresiones de corchetes. Por ejemplo, coincide con las letras mayúsculas y minúsculas "a" y "b". [[:upper:]ab]

Una clase adicional no POSIX comprendida por algunas herramientas es , que generalmente se define como más subrayado. Esto refleja el hecho de que en muchos lenguajes de programación estos son los caracteres que pueden usarse en identificadores. El editor Vim distingue, además, palabra y palabra de cabeza clases (usando la notación y ) ya que en muchos lenguajes de programación de los caracteres que pueden comenzar un identificador no son los mismos que los que pueden ocurrir en otras posiciones: los números son generalmente excluidos, por lo que un identificador se vería como o en notación POSIX. [:word:][:alnum:]\w\h\h\w*[[:alpha:]_][[:alnum:]_]*

Tenga en cuenta que lo que los estándares de expresiones regulares POSIX llaman clases de caracteres se denominan comúnmente clases de caracteres POSIX en otros sabores de expresiones regulares que las admiten. Con la mayoría de los otros sabores de expresiones regulares, el término clase de caracteres se usa para describir lo que POSIX llama expresiones de corchetes .

Perl y PCRE

Debido a su poder expresivo y (relativa) facilidad de lectura, muchas otras utilidades y lenguajes de programación han adoptado una sintaxis similar a la de Perl , por ejemplo, Java , JavaScript , Julia , Python , Ruby , Qt , Microsoft's .NET Framework y XML. Esquema . Algunos lenguajes y herramientas como Boost y PHP admiten varios tipos de expresiones regulares. Las implementaciones de expresiones regulares derivadas de Perl no son idénticas y generalmente implementan un subconjunto de características que se encuentran en Perl 5.0, lanzado en 1994. Perl a veces incorpora características que inicialmente se encuentran en otros lenguajes. Por ejemplo, Perl 5.10 implementa extensiones sintácticas desarrolladas originalmente en PCRE y Python.

Coincidencia perezosa

En Python y algunas otras implementaciones (por ejemplo, Java), los tres cuantificadores comunes ( *, +y ?) son codiciosos por defecto porque coinciden con tantos caracteres como sea posible. La expresión regular ".+"(incluidas las comillas dobles) aplicada a la cadena

"Ganymede," he continued, "is the largest moon in the Solar System."

coincide con toda la línea (porque toda la línea comienza y termina con comillas dobles) en lugar de coincidir solo con la primera parte "Ganymede,",. Sin embargo, los cuantificadores mencionados anteriormente pueden volverse perezosos o mínimos o reacios , haciendo coincidir la menor cantidad de caracteres posible, agregando un signo de interrogación: ".+?"solo coincidencias "Ganymede,".

Sin embargo, la oración completa aún puede coincidir en algunas circunstancias. El operador de signo de interrogación no cambia el significado del operador de punto, por lo que aún puede coincidir con las comillas dobles en la entrada. Un patrón como ".*?" EOFseguirá coincidiendo con toda la entrada si esta es la cadena:

"Ganymede," he continued, "is the largest moon in the Solar System." EOF

Para asegurarse de que las comillas dobles no puedan ser parte de la coincidencia, el punto debe reemplazarse (por ejemplo "[^"]*"). Esto coincidirá con una parte de texto citado sin comillas dobles adicionales. (Al eliminar la posibilidad de hacer coincidir el sufijo fijo, es decir ", esto también ha transformado la coincidencia perezosa en una coincidencia codiciosa, por lo ?que ya no se necesita).

Emparejamiento posesivo

En Java, los cuantificadores pueden hacerse posesivos agregando un signo más, que deshabilita el retroceso (en un motor de retroceso), incluso si hacerlo permitiría que la coincidencia general tenga éxito: mientras que la expresión regular se ".*"aplica a la cadena

"Ganymede," he continued, "is the largest moon in the Solar System."

coincide con toda la línea, la expresión regular ".*+"no se corresponde en absoluto , porque .*+consume la entrada completa, incluyendo la final ". Por lo tanto, los cuantificadores posesivos son más útiles con clases de caracteres negadas, por ejemplo "[^"]*+", que coincide "Ganymede,"cuando se aplica a la misma cadena.

Otra extensión común que cumple la misma función es la agrupación atómica, que deshabilita el retroceso para un grupo entre paréntesis. La sintaxis típica es (?> Grupo) . Por ejemplo, mientras ^ (wi | w) i $ coincide con wi y wii , ^ (?> Wi | w) i $ solo coincide con wii porque el motor tiene prohibido retroceder e intente configurar el grupo como "w".

Los cuantificadores posesivos son más fáciles de implementar que los cuantificadores codiciosos y perezosos, y suelen ser más eficientes en tiempo de ejecución.

Patrones para lenguajes no regulares

Muchas de las características que se encuentran en prácticamente todas las bibliotecas de expresiones regulares modernas proporcionan un poder expresivo que supera a los lenguajes regulares . Por ejemplo, muchas implementaciones permiten agrupar subexpresiones entre paréntesis y recordar el valor que coinciden en la misma expresión ( backreferences ). Esto significa que, entre otras cosas, un patrón puede coincidir con cadenas de palabras repetidas como "papá" o "WikiWiki", llamadascuadradosen la teoría del lenguaje formal. El patrón de estas cadenas es(.+)\1.

El lenguaje de los cuadrados no es regular, ni está libre de contexto , debido al lema de bombeo . Sin embargo, la coincidencia de patrones con un número ilimitado de referencias inversas, respaldada por numerosas herramientas modernas, sigue siendo sensible al contexto . El problema general de hacer coincidir cualquier número de referencias inversas es NP-completo , que crece exponencialmente por el número de grupos de referencias inversas utilizados.

Sin embargo, muchas herramientas, bibliotecas y motores que proporcionan tales construcciones todavía usan el término expresión regular para sus patrones. Esto ha llevado a una nomenclatura en la que el término expresión regular tiene diferentes significados en la teoría del lenguaje formal y la coincidencia de patrones. Por esta razón, algunas personas han comenzado a usar el término regex , regexp o simplemente patrón para describir este último. Larry Wall , autor del lenguaje de programación Perl, escribe en un ensayo sobre el diseño de Raku :

Las "expresiones regulares" […] sólo están relacionadas marginalmente con las expresiones regulares reales. Sin embargo, el término ha crecido con las capacidades de nuestros motores de coincidencia de patrones, por lo que no voy a intentar luchar contra la necesidad lingüística aquí. Sin embargo, generalmente los llamaré "regexes" (o "regexen", cuando estoy de humor anglosajón).

Afirmación Mira atrás Mirar hacia el futuro
Positivo (? <= patrón ) (? = patrón )
Negativo (? <! patrón ) (? ! patrón )
Aserciones de retrospectiva y anticipación
en expresiones regulares de Perl

Otras características que no se encuentran en la descripción de lenguajes regulares incluyen afirmaciones. Estos incluyen los ubicuos ^ y $ , así como algunas extensiones más sofisticadas como lookaround. Definen el entorno de una coincidencia y no se extienden a la coincidencia en sí, una característica que solo es relevante para el caso de uso de la búsqueda de cadenas. Algunos de ellos se pueden simular en un lenguaje regular tratando el entorno como parte del lenguaje también.

Implementaciones y tiempos de ejecución

Hay al menos tres algoritmos diferentes que deciden si una expresión regular determinada coincide con una cadena y de qué manera.

El más antiguo y más rápido se basa en un resultado en la teoría del lenguaje formal que permite que cada autómata finito no determinista (NFA) se transforme en un autómata finito determinista (DFA). El DFA puede construirse explícitamente y luego ejecutarse en la cadena de entrada resultante, un símbolo a la vez. La construcción del DFA para una expresión regular de tamaño m tiene el costo de tiempo y memoria de O (2 m ), pero se puede ejecutar en una cadena de tamaño n en el tiempo O ( n ). Tenga en cuenta que el tamaño de la expresión es el tamaño después de que se hayan ampliado las abreviaturas, como los cuantificadores numéricos.

Un enfoque alternativo es simular la NFA directamente, esencialmente construyendo cada estado de DFA a pedido y luego descartándolo en el siguiente paso. Esto mantiene implícito el DFA y evita el costo de construcción exponencial, pero el costo de funcionamiento aumenta a O ( mn ). El enfoque explícito se denomina algoritmo DFA y el enfoque implícito, algoritmo NFA. Agregar almacenamiento en caché al algoritmo NFA a menudo se denomina algoritmo "Lazy DFA", o simplemente algoritmo DFA sin hacer una distinción. Estos algoritmos son rápidos, pero usarlos para recordar subexpresiones agrupadas, cuantificación diferida y características similares es complicado. Las implementaciones modernas incluyen la familia re1-re2-sregex basada en el código de Cox.

El tercer algoritmo consiste en hacer coincidir el patrón con la cadena de entrada retrocediendo . Este algoritmo se denomina comúnmente NFA, pero esta terminología puede resultar confusa. Su tiempo de ejecución puede ser exponencial, lo que las implementaciones simples exhiben cuando se comparan con expresiones como las que contienen alternancia y cuantificación ilimitada y obligan al algoritmo a considerar un número exponencialmente creciente de sub-casos. Este comportamiento puede provocar un problema de seguridad denominado Denegación de servicio de expresión regular (ReDoS). (a|aa)*b

Aunque las implementaciones de retroceso solo brindan una garantía exponencial en el peor de los casos, brindan mucha mayor flexibilidad y poder expresivo. Por ejemplo, cualquier implementación que permita el uso de backreferences, o implemente las diversas extensiones introducidas por Perl, debe incluir algún tipo de backtracking. Algunas implementaciones intentan proporcionar lo mejor de ambos algoritmos ejecutando primero un algoritmo DFA rápido y revertir a un algoritmo de retroceso potencialmente más lento solo cuando se encuentra una referencia inversa durante la coincidencia. GNU grep (y el subyacente gnulib DFA) utiliza dicha estrategia.

Los algoritmos de tiempo de ejecución sublineales se han logrado utilizando algoritmos basados ​​en Boyer-Moore (BM) y técnicas de optimización de DFA relacionadas, como el escaneo inverso. GNU grep, que admite una amplia variedad de sintaxis y extensiones POSIX, usa BM para un prefiltrado de primer paso y luego usa un DFA implícito. Wu agrep , que implementa el emparejamiento aproximado, combina el prefiltrado en el DFA en BDM (emparejamiento DAWG hacia atrás). El BNDM de NR-grep amplía la técnica BDM con el paralelismo Shift-Or a nivel de bits.

Existen algunas alternativas teóricas al retroceso de referencias inversas, y sus "exponentes" son más dóciles en el sentido de que solo están relacionados con el número de referencias inversas, una propiedad fija de algunos lenguajes de expresiones regulares como POSIX. Un método ingenuo que duplica un NFA sin retroceso para cada nota de referencia inversa tiene una complejidad de tiempo y espacio para un pajar de longitud n y k referencias inversas en la RegExp. Un trabajo teórico muy reciente basado en autómatas de memoria da un límite más estrecho basado en los nodos variables "activos" usados, y una posibilidad polinomial para algunas expresiones regulares con referencias anteriores.

Unicode

En términos teóricos, cualquier conjunto de tokens puede coincidir con expresiones regulares siempre que esté predefinido. En términos de implementaciones históricas, las expresiones regulares se escribieron originalmente para usar caracteres ASCII como su conjunto de tokens, aunque las bibliotecas de expresiones regulares han admitido muchos otros conjuntos de caracteres . Muchos motores de expresiones regulares modernos ofrecen al menos algo de soporte para Unicode . En la mayoría de los aspectos, no importa cuál sea el conjunto de caracteres, pero surgen algunos problemas al extender las expresiones regulares para admitir Unicode.

  • Codificación admitida . Algunas bibliotecas de expresiones regulares esperan trabajar en alguna codificación particular en lugar de en caracteres Unicode abstractos. Muchos de estos requieren la codificación UTF-8 , mientras que otros pueden esperar UTF-16 o UTF-32 . Por el contrario, Perl y Java son independientes de las codificaciones, en lugar de operar con caracteres decodificados internamente.
  • Gama Unicode admitida . Muchos motores de expresiones regulares solo admiten el plano multilingüe básico , es decir, los caracteres que se pueden codificar con solo 16 bits. Actualmente (a partir de 2016) solo unos pocos motores de expresiones regulares (por ejemplo, Perl y Java) pueden manejar el rango completo de Unicode de 21 bits.
  • Ampliación de construcciones orientadas a ASCII a Unicode . Por ejemplo, en las implementaciones basadas en ASCII, los rangos de carácter de la forma [x-y]son válidas donde x y y tienen puntos de código en el rango [0x00,0x7F] y punto de código ( x ) ≤ punto de código ( y ). La extensión natural de tales rangos de caracteres a Unicode simplemente cambiaría el requisito de que los puntos finales estén en [0x00,0x7F] por el requisito de que estén en [0x0000,0x10FFFF]. Sin embargo, en la práctica, este no suele ser el caso. Algunas implementaciones, como la de gawk , no permiten que los rangos de caracteres crucen bloques Unicode. Un rango como [0x61,0x7F] es válido ya que ambos extremos caen dentro del bloque de latín básico, al igual que [0x0530,0x0560] ya que ambos extremos caen dentro del bloque armenio, pero un rango como [0x0061,0x0532] no es válido porque incluye múltiples bloques Unicode. Otros motores, como el del editor Vim , permiten el cruce de bloques, pero los valores de los caracteres no deben estar separados por más de 256.
  • Insensibilidad a mayúsculas y minúsculas . Algunas banderas que no distinguen entre mayúsculas y minúsculas afectan solo a los caracteres ASCII. Otras banderas afectan a todos los personajes. Algunos motores tienen dos indicadores diferentes, uno para ASCII y otro para Unicode. También varía exactamente qué personajes pertenecen a las clases POSIX.
  • Primos de la insensibilidad a mayúsculas y minúsculas . Como ASCII tiene distinción entre mayúsculas y minúsculas, la insensibilidad entre mayúsculas y minúsculas se convirtió en una característica lógica en la búsqueda de texto. Unicode introdujo scripts alfabéticos sin caso como Devanagari . Para estos, la distinción entre mayúsculas y minúsculas no es aplicable. Para guiones como el chino, parece lógica otra distinción: entre tradicional y simplificado. En las escrituras árabes, se puede desear insensibilidad a la posición inicial, medial, final y aislada . En japonés, la insensibilidad entre hiragana y katakana a veces es útil.
  • Normalización . Unicode tiene caracteres combinados . Al igual que las máquinas de escribir antiguas, los caracteres básicos simples (espacios en blanco, signos de puntuación, símbolos, dígitos o letras) pueden ir seguidos de uno o más símbolos sin espacios (generalmente diacríticos, como acentos que modifican letras) para formar un solo carácter imprimible; pero Unicode también proporciona un conjunto limitado de caracteres precompuestos, es decir, caracteres que ya incluyen uno o más caracteres combinados. Una secuencia de un carácter base + caracteres de combinación debe coincidir con el carácter único precompuesto idéntico (solo algunas de estas secuencias de combinación se pueden precomponer en un solo carácter Unicode, pero son posibles infinitas otras secuencias de combinación en Unicode y necesarias para varios idiomas , usando uno o más caracteres de combinación después de un carácter de base inicial; estas secuencias de combinación pueden incluir un carácter de base o caracteres de combinación parcialmente precompuestos, pero no necesariamente en orden canónico y no necesariamente usando las precomposiciones canónicas). El proceso de estandarizar secuencias de un carácter base + combinación de caracteres descomponiendo estas secuencias canónicamente equivalentes , antes de reordenarlas en orden canónico (y opcionalmente recomponer algunos caracteres de combinación en el carácter base inicial) se llama normalización.
  • Nuevos códigos de control . Unicode introdujo, entre otros, marcas de orden de bytes y marcadores de dirección de texto. Es posible que estos códigos deban tratarse de una manera especial.
  • Introducción de clases de caracteres para bloques Unicode, scripts y muchas otras propiedades de caracteres . Las propiedades del bloque son mucho menos útiles que las propiedades del script, porque un bloque puede tener puntos de código de varios scripts diferentes y un script puede tener puntos de código de varios bloques diferentes. En Perl y la java.util.regexbiblioteca, las propiedades del formulario \p{InX}o los \p{Block=X}caracteres coincidentes en el bloque X y / \P{InX}o \P{Block=X}coincide con los puntos de código que no están en ese bloque. Del mismo modo, \p{Armenian}, \p{IsArmenian}, o \p{Script=Armenian}cualquier carácter en el guión armenio. En general, \p{X}coincide con cualquier carácter, ya sea con la propiedad binaria X o la categoría general X . Por ejemplo, \p{Lu}, \p{Uppercase_Letter}, o \p{GC=Lu}coincide con cualquier letra mayúscula. Propiedades binarias que son no categorías generales incluyen \p{White_Space}, \p{Alphabetic}, \p{Math}, y \p{Dash}. Ejemplos de propiedades no binarios son \p{Bidi_Class=Right_to_Left}, \p{Word_Break=A_Letter}, y \p{Numeric_Value=10}.

Usos

Las expresiones regulares son útiles en una amplia variedad de tareas de procesamiento de texto y, de manera más general , procesamiento de cadenas , donde los datos no necesitan ser textuales. Las aplicaciones comunes incluyen la validación de datos , el raspado de datos (especialmente el raspado web ), la manipulación de datos , el análisis simple , la producción de sistemas de resaltado de sintaxis y muchas otras tareas.

Si bien las expresiones regulares serían útiles en los motores de búsqueda de Internet , procesarlas en toda la base de datos podría consumir recursos informáticos excesivos según la complejidad y el diseño de la expresión regular. Aunque en muchos casos los administradores del sistema pueden ejecutar consultas basadas en expresiones regulares internamente, la mayoría de los motores de búsqueda no ofrecen soporte de expresiones regulares al público. Las excepciones notables incluyen Google Code Search y Exalead . Sin embargo, Google Code Search se cerró en enero de 2012.

Ejemplos de

Las reglas de sintaxis específicas varían según la implementación específica, el lenguaje de programación o la biblioteca en uso. Además, la funcionalidad de las implementaciones de expresiones regulares puede variar entre versiones .

Debido a que las expresiones regulares pueden ser difíciles de explicar y comprender sin ejemplos, los sitios web interactivos para probar las expresiones regulares son un recurso útil para aprender las expresiones regulares mediante la experimentación. Esta sección proporciona una descripción básica de algunas de las propiedades de las expresiones regulares a modo de ilustración.

Las siguientes convenciones se utilizan en los ejemplos.

metacharacter(s) ;; the metacharacters column specifies the regex syntax being demonstrated
=~ m//           ;; indicates a regex match operation in Perl
=~ s///          ;; indicates a regex substitution operation in Perl

También vale la pena señalar que estas expresiones regulares son todas sintaxis similar a Perl. Las expresiones regulares POSIX estándar son diferentes.

A menos que se indique lo contrario, los siguientes ejemplos se ajustan al lenguaje de programación Perl , versión 5.8.8, 31 de enero de 2006. Esto significa que otras implementaciones pueden carecer de soporte para algunas partes de la sintaxis que se muestra aquí (por ejemplo, expresión regular básica frente a extendida, \( \)frente a otras implementaciones. (), o falta de en \dlugar de POSIX [:digit:] ).

La sintaxis y las convenciones utilizadas en estos ejemplos coinciden también con las de otros entornos de programación.

Metacaracteres Descripción Ejemplo
. Normalmente coincide con cualquier carácter excepto con una nueva línea.
Entre corchetes, el punto es literal.
$string1 = "Hello World\n";
if ($string1 =~ m/...../) {
  print "$string1 has length >= 5.\n";
}

Producción:

Hello World
 has length >= 5.
( ) Agrupa una serie de elementos de patrón en un solo elemento.
Al coincidir con un patrón dentro de paréntesis, puede utilizar cualquiera de $1, $2, ... más tarde para referirse al patrón detectado previamente.
$string1 = "Hello World\n";
if ($string1 =~ m/(H..).(o..)/) {
  print "We matched '$1' and '$2'.\n";
}

Producción:

We matched 'Hel' and 'o W'.
+ Coincide con el elemento de patrón anterior una o más veces.
$string1 = "Hello World\n";
if ($string1 =~ m/l+/) {
  print "There are one or more consecutive letter \"l\"'s in $string1.\n";
}

Producción:

There are one or more consecutive letter "l"'s in Hello World.
? Coincide con el elemento de patrón anterior cero o una vez.
$string1 = "Hello World\n";
if ($string1 =~ m/H.?e/) {
  print "There is an 'H' and a 'e' separated by ";
  print "0-1 characters (e.g., He Hue Hee).\n";
}

Producción:

There is an 'H' and a 'e' separated by 0-1 characters (e.g., He Hue Hee).
? Modifica el *, +, ?o {M,N}'d expresiones regulares que viene antes para que coincida con el menor número de veces posible.
$string1 = "Hello World\n";
if ($string1 =~ m/(l.+?o)/) {
  print "The non-greedy match with 'l' followed by one or ";
  print "more characters is 'llo' rather than 'llo Wo'.\n";
}

Producción:

The non-greedy match with 'l' followed by one or more characters is 'llo' rather than 'llo Wo'.
* Coincide con el elemento de patrón anterior cero o más veces.
$string1 = "Hello World\n";
if ($string1 =~ m/el*o/) {
  print "There is an 'e' followed by zero to many ";
  print "'l' followed by 'o' (e.g., eo, elo, ello, elllo).\n";
}

Producción:

There is an 'e' followed by zero to many 'l' followed by 'o' (e.g., eo, elo, ello, elllo).
{M,N} Denota el recuento mínimo de coincidencias M y máximo N.
N se puede omitir y M puede ser 0: {M}coincide con "exactamente" M veces; {M,}coincide con "al menos" M veces; {0,N}coincide con "como máximo" N veces.
x* y+ z?es por tanto equivalente a x{0,} y{1,} z{0,1}.
$string1 = "Hello World\n";
if ($string1 =~ m/l{1,2}/) {
  print "There exists a substring with at least 1 ";
  print "and at most 2 l's in $string1\n";
}

Producción:

There exists a substring with at least 1 and at most 2 l's in Hello World
[…] Denota un conjunto de posibles coincidencias de caracteres.
$string1 = "Hello World\n";
if ($string1 =~ m/[aeiou]+/) {
  print "$string1 contains one or more vowels.\n";
}

Producción:

Hello World
 contains one or more vowels.
| Separa posibilidades alternativas.
$string1 = "Hello World\n";
if ($string1 =~ m/(Hello|Hi|Pogo)/) {
  print "$string1 contains at least one of Hello, Hi, or Pogo.";
}

Producción:

Hello World
 contains at least one of Hello, Hi, or Pogo.
\b Coincide con un límite de ancho cero entre un carácter de clase de palabra (ver a continuación) y un carácter de clase que no es de palabra o un borde; igual que

(^\w|\w$|\W\w|\w\W).

$string1 = "Hello World\n";
if ($string1 =~ m/llo\b/) {
  print "There is a word that ends with 'llo'.\n";
}

Producción:

There is a word that ends with 'llo'.
\w Coincide con un carácter alfanumérico, incluido "_";
igual que [A-Za-z0-9_]en ASCII, y
[\p{Alphabetic}\p{GC=Mark}\p{GC=Decimal_Number}\p{GC=Connector_Punctuation}]

en Unicode, donde la Alphabeticpropiedad contiene más de letras latinas y la Decimal_Numberpropiedad contiene más de dígitos árabes.

$string1 = "Hello World\n";
if ($string1 =~ m/\w/) {
  print "There is at least one alphanumeric ";
  print "character in $string1 (A-Z, a-z, 0-9, _).\n";
}

Producción:

There is at least one alphanumeric character in Hello World
 (A-Z, a-z, 0-9, _).
\W Coincide con un carácter no alfanumérico, excluyendo "_";
igual que [^A-Za-z0-9_]en ASCII, y
[^\p{Alphabetic}\p{GC=Mark}\p{GC=Decimal_Number}\p{GC=Connector_Punctuation}]

en Unicode.

$string1 = "Hello World\n";
if ($string1 =~ m/\W/) {
  print "The space between Hello and ";
  print "World is not alphanumeric.\n";
}

Producción:

The space between Hello and World is not alphanumeric.
\s Coincide con un carácter de espacio en blanco,
que en ASCII son tabulación, avance de línea, avance de página, retorno de carro y espacio;
en Unicode, también coincide con los espacios sin interrupciones, la siguiente línea y los espacios de ancho variable (entre otros).
$string1 = "Hello World\n";
if ($string1 =~ m/\s.*\s/) {
  print "In $string1 there are TWO whitespace characters, which may";
  print " be separated by other characters.\n";
}

Producción:

In Hello World
 there are TWO whitespace characters, which may be separated by other characters.
\S Coincide con cualquier cosa menos un espacio en blanco.
$string1 = "Hello World\n";
if ($string1 =~ m/\S.*\S/) {
  print "In $string1 there are TWO non-whitespace characters, which";
  print " may be separated by other characters.\n";
}

Producción:

In Hello World
 there are TWO non-whitespace characters, which may be separated by other characters.
\d Coincide con un dígito;
igual que [0-9]en ASCII;
en Unicode, igual que la propiedad \p{Digit}o \p{GC=Decimal_Number}, que en sí misma es la misma que la \p{Numeric_Type=Decimal}propiedad.
$string1 = "99 bottles of beer on the wall.";
if ($string1 =~ m/(\d+)/) {
  print "$1 is the first number in '$string1'\n";
}

Producción:

99 is the first number in '99 bottles of beer on the wall.'
\D Coincide con un no dígito;
lo mismo que [^0-9]en ASCII o \P{Digit}en Unicode.
$string1 = "Hello World\n";
if ($string1 =~ m/\D/) {
  print "There is at least one character in $string1";
  print " that is not a digit.\n";
}

Producción:

There is at least one character in Hello World
 that is not a digit.
^ Coincide con el comienzo de una línea o cadena.
$string1 = "Hello World\n";
if ($string1 =~ m/^He/) {
  print "$string1 starts with the characters 'He'.\n";
}

Producción:

Hello World
 starts with the characters 'He'.
$ Coincide con el final de una línea o cadena.
$string1 = "Hello World\n";
if ($string1 =~ m/rld$/) {
  print "$string1 is a line or string ";
  print "that ends with 'rld'.\n";
}

Producción:

Hello World
 is a line or string that ends with 'rld'.
\A Coincide con el comienzo de una cadena (pero no con una línea interna).
$string1 = "Hello\nWorld\n";
if ($string1 =~ m/\AH/) {
  print "$string1 is a string ";
  print "that starts with 'H'.\n";
}

Producción:

Hello
World
 is a string that starts with 'H'.
\z Coincide con el final de una cadena (pero no con una línea interna).
$string1 = "Hello\nWorld\n";
if ($string1 =~ m/d\n\z/) {
  print "$string1 is a string ";
  print "that ends with 'd\\n'.\n";
}

Producción:

Hello
World
 is a string that ends with 'd\n'.
[^…] Coincide con todos los caracteres excepto los que están entre corchetes.
$string1 = "Hello World\n";
if ($string1 =~ m/[^abc]/) {
 print "$string1 contains a character other than ";
 print "a, b, and c.\n";
}

Producción:

Hello World
 contains a character other than a, b, and c.

Inducción

Las expresiones regulares a menudo se pueden crear ("inducir" o "aprender") basándose en un conjunto de cadenas de ejemplo. Esto se conoce como inducción de lenguajes regulares y es parte del problema general de inducción gramatical en la teoría del aprendizaje computacional . Formalmente, dados ejemplos de cadenas en un idioma regular, y quizás también dados ejemplos de cadenas que no están en ese idioma regular, es posible inducir una gramática para el idioma, es decir, una expresión regular que genera ese idioma. No todos los lenguajes regulares pueden inducirse de esta forma (ver la identificación del lenguaje en el límite ), pero muchos sí. Por ejemplo, el conjunto de ejemplos {1, 10, 100} y el conjunto negativo (de contraejemplos) {11, 1001, 101, 0} se pueden usar para inducir la expresión regular 1⋅0 * (1 seguido de cero o más 0s).

Ver también

Notas

Referencias

enlaces externos