Publi

Utilizando expresiones regulares en C++ con Glib::Regex

En nuestra vida como programadores, se marca un hito cuando aprendemos a utilizar las expresiones regulares… es más, son como Twitter, cuando lo conoces, entras un par de veces y lo abandonas durante un tiempo, pero cuando llega tu momento, no puedes vivir sin él. Aquí pasa igual, la primera vez que lo ves y lo entiendes dices: “Mira qué curioso”, pero cuando pasa un tiempo, siembre que hay algún problema con cadenas de texto, las expresiones regulares surgen en tu mente.

Normalmente, uno de los comandos que utilizan expresiones regulares comunmente es grep, pero claro, es un sistema demasiado bueno para ser usado sólo en un sitio, por lo que muchos lenguajes tienen sus funciones para operar con ellas, por ejemplo PHP antes tenía ereg_* y ahora tiene preg_*, en Javascript RegExp(), en Java, incluso las Strings pueden trabajar con ellas y así en un montón de lenguajes.

Pero cuando estamos haciendo un proyecto en C++, no tenemos soluciones nativas para esto, por lo que tenemos que recurrir a bibliotecas como Boost o Glib para tener ese soporte… si no queremos darlo nosotros.

En este caso, vamos a hacerlo con Glib, imaginemos que estamos haciendo una plantilla, en la que situaremos palabras clave con % delante y detrás, y más o menos queremos saber dónde encontrar cada una de esas palabras clave.

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
#include <glibmm/regex.h>
#include <glibmm/ustring.h>
#include <iostream>

using namespace std;
using namespace Glib;

int main()
{
  Glib::ustring str1 = "Hola %nombre%, me ha digo %amigo% que eres %ocupacion%.";
  cout << "Cadena original: "<< str1 << endl;

  Glib::RefPtr<Regex> myr = Regex::create("%[a-z]*%");
  MatchInfo minfo;

  myr->match(str1, minfo);
  int start, end;
  int i=0;

  while (minfo.matches())
    {
      cout << "Palabra: " << minfo.fetch(0)<<endl;
      if (minfo.fetch_pos(0, start, end))
        {
          cout << "   Inicio:  "<<start<<endl<<"   Fin: "<<end<<endl;
        }
      minfo.next();
      ++i;
    }
    cout << "Apariciones: "<<i<<endl;
}

Para compilar debemos tener glibmm instalada, y hacer

$ g++ -o regex1 regex1.cpp `pkg-config –libs –cflags glibmm-2.4`

En este código podemos ver que se ha aplicado la expresión regular “%[a-z]*%“, es decir, letras minúsculas de la a a la z encerradas entre %. Sobre la cadena de ejemplo y se han encontrado las 3 apariciones de la cadena, devolviéndose la posición de inicio y de fin dentro de la cadena principal.

Para muchos con este uso les bastará, pero en este caso nos devolverá las cadenas como %nombre%, %amigo%, etc, lo que puede que en ciertas ocasiones no sea útil, bueno, siempre podremos hacer algo, pero no será óptimo. Por lo que podremos aplicar paréntesis a la expresión regular, pasando a ser: “%([a-z]*)%“, es decir, nos interesa lo que hay entre paréntesis. Aunque si lo ejecutamos no tendremos mucha suerte… modificaremos un poco el código, porque dentro de cada vez que se cumple cada expresión, podemos obtener cadenas como respuesta, y la primera de ellas es la cadena completa donde se cumple la expresión.

Veamos cómo obtener las subcadenas:

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
#include <glibmm/regex.h>
#include <glibmm/ustring.h>
#include <iostream>

using namespace std;
using namespace Glib;

int main()
{
  Glib::ustring str1 = "Hola %nombre%, me ha digo %amigo% que eres %ocupacion%.";
  cout << "Cadena original: "<< str1 << endl;

  Glib::RefPtr<Regex> myr = Regex::create("%([a-z]*)%");
  MatchInfo minfo;

  myr->match(str1, minfo);
  int start, end;
  int i=0;

  while (minfo.matches())
    {
      cout << "Aparición "<< i+1 << ": "<<endl;

      for (unsigned j = 0; j< minfo.get_match_count(); ++j)
    {
      cout << "Palabra ("<<j<<"): " << minfo.fetch(j)<<endl;
      if (minfo.fetch_pos(j, start, end))
        {
          cout << "   Inicio:  "<<start<<endl<<"   Fin: "<<end<<endl;
        }
    }
      minfo.next();
      ++i;
    }
    cout << "Apariciones: "<<i<<endl;
}

En este caso, estamos iterando get_match_count() veces, este método nos devolverá el número de subcadenas que nos ha devuelto esta expresión en esta aparición, por lo que obteniendo en este caso minfo.fetch(1) tendremos las cadenas “nombre”, “amigo” y “ocupacion”.

Pero vamos a poner un ejemplo un poco mejor, y va a ser una etiqueta XML sencilla.
Como expresión vamos a poner: “<([\\w:]*)( [^<>]*)?>([^<>]*)</\\1>“, lo que significa que encontraremos:

  • Símbolo <
  • una palabra, letras o números
  • posiblemente un espacio y varios caracteres que no son < ni >
  • Símbolo >
  • Varios caracters que no son < ni >
  • Símbolo < y /
  • La misma palabra que se escribió al principio
  • Símbolo >

Luego la cadena con la que vamos a probar es: “Esto es un texto de ejemplo

Y más o menos una respuesta esperada del programa es la siguiente:

Cadena original: <Texto id=”123″>Esto es un texto de ejemplo</Texto>
Aparición 1:
Palabra (0): <Texto id=”123″>Esto es un texto de ejemplo</Texto>
Inicio: 0
Fin: 51
Palabra (1): Texto
Inicio: 1
Fin: 6
Palabra (2): id=”123″
Inicio: 6
Fin: 15
Palabra (3): Esto es un texto de ejemplo
Inicio: 16
Fin: 43
Apariciones: 1

Por lo que con esta pequeña expresión regular hemos conseguido interpretar esta etiqueta, lo cuál puede venir muy bien para nuestros proyectos.

Foto: li xiang (Flickr) CC-by

También podría interesarte...

There are 3 comments left Ir a comentario

  1. Joseph Alberto Morthimer León Lau /
    Usando Google Chrome Google Chrome 45.0.2454.101 en Windows Windows NT

    ayudenme a instalar las librerias en visual c++ , se los agradeceria mucho

    1. Gaspar Fernández / Post Author
      Usando Mozilla Firefox Mozilla Firefox 40.0 en Ubuntu Linux Ubuntu Linux

      Hola, a ver si te vale esto: http://stackoverflow.com/questions/12360492/how-to-configure-glib-on-microsoft-visual-studio-2010 enlaza una guía para configurar GTK con Visual Studio. Glib está incluido dentro de GTK, a lo mejor puedes sacar algo en claro.

      Saludos

  2. Pingback: Cómo hacer pequeñas operaciones matemáticas al reemplazar texto en Emacs – Poesía Binaria /

Leave a Reply