-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathregex.tex
241 lines (199 loc) · 10.2 KB
/
regex.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
%Autor: miguev, faraox
%miguev: 2 + 5
%faraox: 3
\chapter{Expresiones regulares}
\index{Expresiones regulares}
\label{regex.tex}
Las expresiones regulares se comprenden mejor desde su utilidad que
desde su definición, así que vamos a introducirlas con el ejemplo que
utilizan en el libro \cite{mastregex}.
Imagina que necesitas una herramienta para buscar palabras repetidas
en documentos, cosas como ``esto esto'', un problema bastante
frecuente en documentos que son editados una y otra vez (como este
libro).
Tendrías que escribir una solución que: detectara palabras repetidas
de una línea a la siguiente, cuando una palabra está al final de una
línea y también al principio de la siguiente línea; que no tuviera en
cuenta si las letras están en minúsculas o mayúsculas y encontrar
palabras repetidas en medio de código HTML, \LaTeX, \LyX~ u otros
lenguajes de marcado usados en documentación.
Esto es un problema real, y el autor del libro \cite{mastregex}
escribió esta solución y se vió sorprendido por la cantidad de
palabras repetidas que encontró en el propio libro. Este problema
puede resolverse de muchas maneras y en muchos lenguajes de
programación, pero las expresiones regulares son sin duda la
herramienta que hacen este tipo de problemas más fáciles y rápidos de
resolver.
\section{Definición de expresión regular}
Una {\em expresión regular} es un literal (cadena de caracteres) que
define una serie de reglas que debe cumplir una expresión para
considerar que {\em encaja} con la expresión regular. Esto se consigue
utilizando caracteres con significados especiales para {\em describir}
un patrón con el que deben encajar las expresiones.
Los caracteres con significados especiales se denominan {\em
metacaracteres}, y aunque la mayoría son comunes entre los distintos
estilos de expresiones regulares hay diferencias y conviene
estudiarlos desde la herramienta en la que usemos las expresiones
regulares. Así, nos encontramos con expresiones regulares de UNIX, de
VI, de PERL, de Emacs, etc. y no tienen la misma sintaxis exactamente.
Dado que esto no es un curso de programación no veremos las
expresiones regulares al estilo de lenguajes de programación sino al
estilo de los editores de texto.
\section{Expresiones regulares en VI \& VIM}
\index{Expresiones regulares!con VIM }
Una de las funcionalidades más queridas de {\sf VI} es la búsqueda y
\index{VIM!búsqueda y substitución}
sustitución de texto. Para empezar pensemos en simples palabras, por
ejemplo en substituir la palabra ``coche'' por la palabra ``carro''.
El comando para la substitución es {\tt :s} y tiene el siguiente
esquema:
\begin{verbatim}
:rango/busca/sustituye/[gc]
\end{verbatim}
Lo que pongas en {\tt rango} determina la región del fichero que será
afectada por el comando. Puedes poner dos números de línea separados
por coma para afectar a todas las líneas entre esas dos (ambas
inclusive), o bien substituir el número de la segunda línea por un
\verb.$. para extender la región afectada hasta el final del fichero.
Si en lugar de líneas poner \verb.%. afectará a todo el fichero.
Las opciones {\tt g} y {\tt c} del final son opcionales. La opción
{\tt g} hace que se substituyan todas las ocurrencias en cada línea,
ya que si no la especificas sólo se substituye la primera ocurrencia
de cada línea. La opción {\tt c} hace que {\tt VI} pida confirmación
antes de substituir cada ocurrencia.
La expresión {\tt busca} es el patrón que {\sf VIM} buscará. Puede ser
una palabra, o más en general una {\em expresión regular}. La
expresión {\tt substituye} es el patrón que {\sf VIM} utilizará para
substituir en las ocurrencias, y también puede ser una {\em expresión
regular}.
En {\sf VI} las expresiones regulares utilizan los siguientes
metacaracteres: \verb_. ^ $ [ ] \ * - /_
El punto (\verb_._) encaja con cualquier caracter, \verb.$. con el
final de la línea, \verb.^. con el principio de la línea cuando es el
primero en la expresión regular, mientras que en otro caso encaja con
cualquier caracter que {\bf no} sea el que le suceda. Los caracteres
\verb.-., \verb.[. y \verb.]. permiten definir rangos, \verb.*.
extiende el significado de la expresión que le preceda a ninguna o
varias ocurrencias de la misma. La barra \verb./. se utiliza para
separar los patrones de búsqueda. Para utilizar alguno de estos
caracteres de forma que encajen consigo mismos (por ejemplo para
buscar un punto en el texto) hay que {\em escaparlos} anteponiéndoles
una barra invertida (\verb.\.).
Otros caracteres adquieren un significado especial cuando son
precedidos de la barra invertida. Así \verb.\|. es el operador ``o'',
es decir la expresión \verb.casa\|coche. encaja con {\tt casa} y con
{\tt coche}. Los símbolos de desigualdad permiten delimitar palabras
en un patrón, usando \verb.\<. que encaja con el principio de palabra
y \verb.\>. con el final. Así podremos sustituir la palabra {\tt vi}
por {\tt vim} sin que cambien palabras del texto como {\tt vivir}.
\begin{verbatim}
:s/\<vi\>/vim
\end{verbatim}
Podemos utilizar el carácter \verb.^. para indicar que no exista
ningun carácter antes de la expresión regular que queremos sustituir
en esa línea, y el carácter \verb.$. para indica que no exista ningun
carácter despuéas de la expresión regular que queremos sustituir en
usa línea. Vamos a ver unos ejemplos:
\begin{verbatim}
:s/^vi/vim/g
\end{verbatim}
En este ejemplo, se cambia la palabra {\tt vi} por {\tt vim} si no
existe ningun carácter delante de la palabra {\tt vi}.
\begin{verbatim}
:s/vi$/vim
\end{verbatim}
En el anterior ejemplo, se sustituye la palabra {\tt vi} por {\tt vim}
que se encuentre al final de una línea.
\begin{verbatim}
:s/^vi$/vim
\end{verbatim}
Los metacaracteres nos permiten una gran flexibilidad a la hora de
trabajar con expresiones regulares.
\begin{table}[htbp]
\centering
\index{Expresiones regulares!metacaracteres con VIM }
\begin{tabular}{|c|l|}
\hline
{\tt .} & Cualquier caracter \\
{\tt \verb.\s.} & Espacios en blanco \\
{\tt \verb.\d.} & Digitos \\
{\tt \verb.\h.} & Cualquier letra \\
{\tt \verb.\w.} & Letras y digitos \\
{\tt \verb.\l.} & Letras minúsculas \\
{\tt \verb.\u.} & Letras mayúsculas \\
\hline
\end{tabular}
\caption{Metacaracteres en las expresiones regulares de VI}
\end{table}
Vamos a poner un ejemplo con este tipo de comandos. Si queremos buscar
en el texto fechas con el formato DD/MM/AAAA, lo que haríamos sería:
\begin{verbatim}
/\d\d\/\d\d\/\d\d\d\d
\end{verbatim}
O por ejemplo si buscamos palabras que empiezen con mayúsculas de un
modo sencillo podemos hacer:
\begin{verbatim}
/\<\u
\end{verbatim}
Ahora vamos a introducir unos elementos nuevos para hacer reemplazos
y busquedas más ``profesionales''. Uno de ellos son los {\em
cuantificadores}.\index{VIM!expresiones regulares!cuantificadores} Si
necesitamos buscar en un documento grandes grupos de números
de 9 cifras por ejemplo nos resultaría muy laborioso escribir
\verb./\d\d\d\d\d\d\d\d\d.. Los cuantificadores son diversas
expresiones que nos permiten definir el número de veces que aparecerá
el tipo de caracter que queremos buscar. Los más importantes son
\verb.\+., relaciona el caracter que aparece una o más veces en una
palabra, \verb.\=., relaciona el caracter que aparece 0, 1 o más veces
en una palabra. Con \verb.\{n,m}. relaciona el caracter si se
encuentra entre n y m veces. La expresión \verb.\{n}. relaciona el
caracter si se encutra n veces. Así en el ejemplo anterior podríamos
usar:
\begin{verbatim}
/\d\{9}
\end{verbatim}
y nos mostraría las expresiones que contengan 9 digitos.
Podemos combinar los cuantificadores con los rangos de caracteres para
conseguir mejores resultados. Los rangos de expresiones regulares son
definidos dentro de \verb.[].. Por ejemplo, \verb./[a-h]. buscará en
el texto todos las letras entre la a y la h, ambas inclusive,
\verb./[A-H]. haría lo mismo en mayúsculas. También existe un
valor negativo en los rangos, es el {\tt \verb.^.}. El comando
\verb./[^j-z]. mostrará todas las letras minúsculas anteriores a la j.
Para buscar mayúsculas o minúsculas hay algo mejor que
los rangos \verb.[a-z]. y \verb.[A-Z]., que son las {\em
clases}\index{VIM!expresiones regulares!clases}. Las clases se
refieren mediante palabras encerradas entre \verb.[[:. y \verb.:]].,
por lo que para buscar una expresión mediante clases el patrón
de búsqueda deberá contener \verb.[[:clase:]]. Las clases que nos
interesan son:
\begin{table}[htbp]
\centering
\begin{tabular}{|c|l|}
\hline
{\tt \verb.[[:lower:]].} & cualquier letra minúscula (incluida {\tt ñ}) \\
{\tt \verb.[[:upper:]].} & cualquier letra mayúscula (incluida {\tt Ñ}) \\
{\tt \verb.[[:alpha:]].} & cualquier letra \\
{\tt \verb.[[:digit:]].} & cualquier dígito \\
\hline
\end{tabular}
\caption{Metacaracteres en las expresiones regulares de VI}
\end{table}
Tambien podemos cambiar el orden de las frases de todo
un texto o de zonas específicas, utilizando los {\em
agrupadores}\index{VIM!expresiones regulares!agrupadores}. Se trata de
crear grupos de expresiones que luego para sustituir utilizaremos
expresiones que nos permitan reordenarlos. Para definir un grupo
se utiliza \verb.\(\)., el texto que se encuentre entre esos el
paréntesis ``escapados'' será la expresion que buscará. Por ejemplo,
estamos usando un archivo con varios nombres de ciudades, pero para
poder utilizarlo necesitamos que todos esten al principio de la línea,
sin ningun espacio, podemos utilizar el siguiente comando:
\begin{verbatim}
:%s/^\(\s\+\)\(\w\+\)/\2/g
\end{verbatim}
El anterior comando busca en todo el documento (\verb.%.) que contenga
cualquier número espacios al principio de la línea (\verb.\(\s\+\).) y
que detrás contenga algún texto(\verb.\(\w\+\)). y lo sustituye por la
exresión(\verb.\2.), es decir, solo mantiene el grupo \verb.\2., el
que contiene la palabra.