NLP y el Uso de Expresiones Regulares
El procesamiento de lenguaje natural es un área sumamente complicada del aprendizaje máquina, del procesamiento estadístico de datos y de la linguística. Para lo cual se han utilizado técnicas desde el conteo de letras, hasta el desarrollo de complejas redes neuronales.
Una de las técnicas básicas para el procesamiento de lenguaje es el uso de expresiones regulares. Una expresión regular es una cadena de caracteres que describe un patrón. El concepto de las expresiones regulares fue desarrollado por Christopher Kleene junto con el de lenguaje regular. Su uso se extendió en la programación mediante las utilidades del sistema Unix en los 60’s y 70’s.
Formalmente los procesadores de expresiones regulares son descritos por la teoría de autómatas, en ella el autómata consume los símbolos del texto y los resultados pueden ser actuar (capturar el símbolo) o no. Idealmente el procesamiento debe hacerse por Autómatas deterministas, o corremos el riesgo de que el autómata nunca acabe de procesar el texto.
Las expresiones regulares describen los patrones que queremos que sean “capturados” a continuación veremos los tipos de patrones mas simples:
Una expresión rtegular entonces, es una manera de describir un patrón para buscar coincidencias en una cadena de texto. Las expresiones regulares pueden servir para resolver los siguientes problemas:
- Buscar un patrón
- Extraer una subcadena
- Reemplazar una subcadena
Una de mis librerías favoritas de expresiones regulares es RE2 la cual fue creada en Google y es utilizada también por Golang. Una de las características determinantes de RE2 es que no permite el uso de back-reference, las cuales no pueden ser implementadas eficientemente y en algunos casos pueden llegar a tener un comportamiento exponencial tanto en procesamiento como en memoria.
Referencia de sintaxis de RE2
Single characters:
.any character, possibly including newline (s=true)[xyz]character class[^xyz]negated character class\dPerl character class\Dnegated Perl character class[[:alpha:]]ASCII character class[[:^alpha:]]negated ASCII character class\pNUnicode character class (one-letter name)\p{Greek}Unicode character class\PNnegated Unicode character class (one-letter name)\P{Greek}negated Unicode character class
Composites:
xy«x» followed by «y»x|y«x» or «y» (prefer «x»)
Repetitions:
x*zero or more «x», prefer morex+one or more «x», prefer morex?zero or one «x», prefer onex{n,m}«n» or «n»+1 or … or «m» «x», prefer morex{n,}«n» or more «x», prefer morex{n}exactly «n» «x»x*?zero or more «x», prefer fewerx+?one or more «x», prefer fewerx??zero or one «x», prefer zerox{n,m}?«n» or «n»+1 or … or «m» «x», prefer fewerx{n,}?«n» or more «x», prefer fewerx{n}?exactly «n» «x»x{} (== x*)NOT SUPPORTED vimx{-} (== x*?)NOT SUPPORTED vimx{-n} (== x{n}?)NOT SUPPORTED vimx= (== x?)NOT SUPPORTED vim
Implementation restriction: The counting forms «x{n,m}», «x{n,}», and «x{n}» reject forms that create a minimum or maximum repetition count above 1000. Unlimited repetitions are not subject to this restriction.
Possessive repetitions:
x*+zero or more «x», possessive NOT SUPPORTEDx++one or more «x», possessive NOT SUPPORTEDx?+zero or one «x», possessive NOT SUPPORTEDx{n,m}+«n» or … or «m» «x», possessive NOT SUPPORTEDx{n,}+«n» or more «x», possessive NOT SUPPORTEDx{n}+exactly «n» «x», possessive NOT SUPPORTED
Grouping:
(re)numbered capturing group (submatch)(?P<name>re)named & numbered capturing group (submatch)(?<name>re)named & numbered capturing group (submatch) NOT SUPPORTED(?'name're)named & numbered capturing group (submatch) NOT SUPPORTED(?:re)non-capturing group(?flags)set flags within current group; non-capturing(?flags:re)set flags during re; non-capturing(?#text)comment NOT SUPPORTED(?|x|y|z)branch numbering reset NOT SUPPORTED(?>re)possessive match of «re» NOT SUPPORTEDre@>possessive match of «re» NOT SUPPORTED vim%(re)non-capturing group NOT SUPPORTED vim
Flags:
icase-insensitive (default false)mmulti-line mode: «^» and «$» match begin/end line in addition to begin/end text (default false)slet «.» match «\n» (default false)Uungreedy: swap meaning of «x*» and «x*?», «x+» and «x+?», etc (default false) Flag syntax is «xyz» (set) or «-xyz» (clear) or «xy-z» (set «xy», clear «z»).
Empty strings:
^at beginning of text or line («m»=true)$at end of text (like «\z» not «\Z») or line («m»=true)\Aat beginning of text\bat ASCII word boundary («\w» on one side and «\W», «\A», or «\z» on the other)\Bnot at ASCII word boundary\Gat beginning of subtext being searched NOT SUPPORTED pcre\Gat end of last match NOT SUPPORTED perl\Zat end of text, or before newline at end of text NOT SUPPORTED\zat end of text(?=re)before text matching «re» NOT SUPPORTED(?!re)before text not matching «re» NOT SUPPORTED(?<=re)after text matching «re» NOT SUPPORTED(?<!re)after text not matching «re» NOT SUPPORTEDre&before text matching «re» NOT SUPPORTED vimre@=before text matching «re» NOT SUPPORTED vimre@!before text not matching «re» NOT SUPPORTED vimre@<=after text matching «re» NOT SUPPORTED vimre@<!after text not matching «re» NOT SUPPORTED vim\zssets start of match (= \K) NOT SUPPORTED vim\zesets end of match NOT SUPPORTED vim\%^beginning of file NOT SUPPORTED vim\%$end of file NOT SUPPORTED vim\%Von screen NOT SUPPORTED vim\%#cursor position NOT SUPPORTED vim\%'mmark «m» position NOT SUPPORTED vim\%23lin line 23 NOT SUPPORTED vim\%23cin column 23 NOT SUPPORTED vim\%23vin virtual column 23 NOT SUPPORTED vim
Escape sequences:
\abell (== \007)\fform feed (== \014)\thorizontal tab (== \011)\nnewline (== \012)\rcarriage return (== \015)\vvertical tab character (== \013)\*literal «», for any punctuation character «»\123octal character code (up to three digits)\x7Fhex character code (exactly two digits)\x{10FFFF}hex character code\Cmatch a single byte even in UTF-8 mode\Q...\Eliteral text «…» even if «…» has punctuation\1backreference NOT SUPPORTED\bbackspace NOT SUPPORTED (use «\010»)\cKcontrol char ^K NOT SUPPORTED (use «\001» etc)\eescape NOT SUPPORTED (use «\033»)\g1backreference NOT SUPPORTED\g{1}backreference NOT SUPPORTED\g{+1}backreference NOT SUPPORTED\g{-1}backreference NOT SUPPORTED\g{name}named backreference NOT SUPPORTED\g<name>subroutine call NOT SUPPORTED\g'name'subroutine call NOT SUPPORTED\k<name>named backreference NOT SUPPORTED\k'name'named backreference NOT SUPPORTED\lXlowercase «X» NOT SUPPORTED\uxuppercase «x» NOT SUPPORTED\L...\Elowercase text «…» NOT SUPPORTED\Kreset beginning of «$0» NOT SUPPORTED\N{name}named Unicode character NOT SUPPORTED\Rline break NOT SUPPORTED\U...\Eupper case text «…» NOT SUPPORTED\Xextended Unicode sequence NOT SUPPORTED\%d123decimal character 123 NOT SUPPORTED vim\%xFFhex character FF NOT SUPPORTED vim\%o123octal character 123 NOT SUPPORTED vim\%u1234Unicode character 0x1234 NOT SUPPORTED vim\%U12345678Unicode character 0x12345678 NOT SUPPORTED vim
Character class elements:
xsingle characterA-Zcharacter range (inclusive)\dPerl character class[:foo:]ASCII character class «foo»\p{Foo}Unicode character class «Foo»\pFUnicode character class «F» (one-letter name)
Named character classes as character class elements:
[\d]digits (== \d)[^\d]not digits (== \D)[\D]not digits (== \D)[^\D]not not digits (== \d)[[:name:]]named ASCII class inside character class (== [:name:])[^[:name:]]named ASCII class inside negated character class (== [:^name:])[\p{Name}]named Unicode property inside character class (== \p{Name})[^\p{Name}]named Unicode property inside negated character class (== \P{Name})
Perl character classes (all ASCII-only):
\ddigits (== [0-9])\Dnot digits (== [^0-9])\swhitespace (== [\t\n\f\r ])\Snot whitespace (== [^\t\n\f\r ])\wword characters (== [0-9A-Za-z_])\Wnot word characters (== [^0-9A-Za-z_])\hhorizontal space NOT SUPPORTED\Hnot horizontal space NOT SUPPORTED\vvertical space NOT SUPPORTED\Vnot vertical space NOT SUPPORTED
ASCII character classes:
[[:alnum:]]alphanumeric (== [0-9A-Za-z])[[:alpha:]]alphabetic (== [A-Za-z])[[:ascii:]]ASCII (== [\x00-\x7F])[[:blank:]]blank (== [\t ])[[:cntrl:]]control (== [\x00-\x1F\x7F])[[:digit:]]digits (== [0-9])[[:graph:]]graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~])[[:lower:]]lower case (== [a-z])[[:print:]]printable (== [ -~] == [ [:graph:]])[[:punct:]]punctuation (== [!-/:-@[-`{-~])[[:space:]]whitespace (== [\t\n\v\f\r ])[[:upper:]]upper case (== [A-Z])[[:word:]]word characters (== [0-9A-Za-z_])[[:xdigit:]]hex digit (== [0-9A-Fa-f])