Expresiones Regulares, Extracción de datos

¿Cómo extraer datos mediante expresiones regulares?

Ahora que hemos explorado las expresiones regulares, las cadenas de caracteres (strings) y bytes, podemos echar mano de las expresiones regulares para poder manipular los datos.

Supongamos que tenemos archivo lista.html como el siguiente.

<ul>
  <li><span class="nombre">Luis</span><span class="apellido">Perez</span></li>
  <li><span class="nombre">Adrian</span><span class="apellido">Romo</span></li>
  <li>
    <span class="nombre">Daniel</span><span class="apellido">Quiroz</span>
  </li>
</ul>

Utilizando expresiones regulares podemos procesar esta cadena de caracteres y obtener la lista de los apellidos.

La solución para este problema es definir una expresión regular que:

  1. Obtener cada una de las lineas.
  2. Cada línea esta compuesta de 3 bloques:
  3. La apertura de la etiqueta span class="name", el valor nombre y el cierre de la etiqueta.
  4. Solo requerimos el valor del nombre.

La propuesta es la siguiente:

[apertura][valor][cierre]
(<span class="nombre">)([^<]+)(</span>)

La expresión regular anterior es una sola, pero he encerrado cada parte de la expresión entre paréntesis, esto permite separarlo en tres partes.

Para realizar esta operación utilizamos la función FindAllSubmatchIndex. La cual recibe un arreglo de bytes y retorna un arreglo con cada una de las coincidencias de la expresión regular, sin embargo estas coincidencias no son el string sino un arreglo de indices el cual contiene:

  • La posición inicial y final de la coincidencia en el arreglo de bytes.
  • La posición inicial y final de la primera expresión encerrada entre paréntesis.
  • La posición inicial y final de la siguiente expresión encerrada entre paréntesis.
  • Así sucesivamente hasta completar la última expresión.

Por ejemplo para la primera coincidencia:

<span class="nombre">Luis</span>
[a,b,c,d,e,f,g,h]

Si del arreglo de bytes imprimiéramos:

  • [posicion[a]:posicion[b]] = <span class="nombre">Luis</span>
  • [posicion[c]:posicion[d]] = <span class="nombre">
  • [posicion[e]:posicion[f]] = Luis
  • [posicion[g]:posicion[h]] = </span>

Vamos a ver el ejemplo completo…

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "regexp"
)

func main() {

    // en donde vamos a capturar los nombres
    var nombres = make([]string, 3)

    // cargar contenido del html
    datosComoBytes, err := ioutil.ReadFile("lista.html")
    if err != nil {
        log.Fatal(err)
    }

    // preparar la expresion regular
    expReg := regexp.MustCompile(`(<span class="nombre">)([^<]+)(</span>)`)

    // ejecutar la busqueda de los indices
    todosLosIndices := expReg.FindAllSubmatchIndex(datosComoBytes, -1)

    // recorrer los resultados y capturar el nombre
    for _, loc := range todosLosIndices {
        nombres = append(nombres, string(datosComoBytes[loc[4]:loc[5]]))
    }

    // imprimir los nombres
    fmt.Println(nombres)
}

Si ejecutamos el programa obtendremos lo siguiente.

[  Luis Adrian Daniel]