Gorp.NET es una nueva biblioteca para crear plantillas reversibles para extraer datos de texto estructurado, basado en la base de código existente de Salesforce Gorp .En esta publicación, hablaré un poco sobre cómo usar la biblioteca para analizar texto estructurado llamado
Gorp (uno de los ejemplos de herramientas que a veces se denominan sistemas de
plantillas de ingeniería inversa ).
¿Qué es una
plantilla reversible en general? Supongamos que tenemos un cierto sistema que nos permite generar el texto que necesitamos en función de los datos iniciales que hemos determinado, de acuerdo con reglas estrictas definidas por la sintaxis de las plantillas. Ahora imaginemos una tarea que tiene un significado opuesto: tenemos un texto que tiene cierta integridad estructural que podría lograrse mediante el uso de un sistema basado en las plantillas del ejemplo anterior. Nuestro objetivo es extraer de este texto los datos de origen sobre la base de los cuales se formaron. Si tratamos de llegar a una cierta sintaxis generalizada para resolver este problema, suministrada al analizador correspondiente, que analiza el texto de entrada en elementos separados, este será un ejemplo de sintaxis para implementar el concepto de plantillas reversibles.
¿Por qué decidí escribir específicamente sobre
Gorp ? El hecho es que decidí tomar este sistema como base para finalizar mi propio proyecto: la historia del proyecto en sí, incluidos algunos detalles de todos los cambios que hice al proyecto original de
Gorp , se pueden encontrar
en el artículo anterior . Aquí nos centraremos con precisión en la parte técnica, incluso en relación con el uso de una versión modificada del motor. Por conveniencia, continuaré llamándolo
Gorp.NET , aunque en realidad no se trata de una versión de
Gorp que no está portada a .NET, sino solo una versión ligeramente pulida y finalizada, todo en el mismo Java. Otra cosa es que el complemento sobre la
propia biblioteca
Gorp (en mi versión) en forma de una biblioteca DLL administrada llamada
BIRMA.NET usa su propio ensamblado especial: el mismísimo
Gorp.NET , que usted mismo puede obtener fácilmente si ejecuta el texto fuente ( la dirección de su repositorio es
https://github.com/S-presso/gorp/ ) a través de la utilidad
IKVM.NET .
Notaré en este momento que para todo tipo de tareas de extracción de datos de cualquier texto estructurado, las herramientas
Gorp.NET en sí mismas serán suficientes para
usted , al menos si tiene un pequeño comando de Java o al menos sabe cómo llamar a métodos de módulos Java externos en sus proyectos en .NET Framework, además de incluir varios tipos de las bibliotecas JVM estándar allí (logré esto a través del mismo
IKVM.NET , que, sin embargo, ahora ya tiene el estado de un proyecto no compatible). Bueno, y qué harás después con los datos extraídos; esto, como dicen, es asunto tuyo.
Gorp y
Gorp.NET solo proporcionan un marco
básico . Algunas bases para el procesamiento posterior de todos esos datos contienen el mencionado
BIRMA.NET . Pero la descripción de la funcionalidad
BIRMA.NET en
sí misma ya es un tema para una publicación separada (aunque ya logré mencionar algo en mi
revisión histórica comparativa previa de las tecnologías BIRMA ). Aquí, mirando hacia el futuro, me permitiré una declaración un tanto audaz de que la tecnología utilizada para describir las plantillas reversibles utilizadas en
Gorp.NET (y, en consecuencia,
BIRMA.NET ) es algo única entre otras manualidades de este tipo (digo " manualidades ”, ya que las grandes empresas de alguna manera todavía no han sido vistas por mí para promover sus propios marcos para estos fines, bueno, tal vez, solo
Salesforce en sí con su implementación original de
Gorp ).
Para la divulgación más completa del concepto y los aspectos técnicos que subyacen al sistema de descripción de plantilla utilizado en Gorp, solo dejo aquí un enlace a la
documentación original en inglés . Todo lo que se indica en él, puede aplicarlo con seguridad en relación con
Gorp.NET . Y ahora te contaré un poco sobre la esencia.
Por lo tanto, la descripción de la plantilla es un tipo de documento de texto (tal vez incluso presentado como una sola línea grande, que se puede pasar al método correspondiente para su procesamiento). Consta de tres partes que contienen descripciones secuenciales de las tres entidades más importantes:
patrones ,
patrones y
muestras (extractos).
El bloque de nivel más bajo aquí son
patrones : solo pueden consistir en expresiones regulares y referencias a otros patrones. El siguiente nivel de la jerarquía está ocupado por
plantillas , cuya descripción también contiene enlaces a patrones, que también pueden nombrarse, así como inclusiones en forma de literales de texto, enlaces a plantillas anidadas y extractores. También hay
patrones paramétricos que no tocaré en este momento (en la documentación fuente hay algunos ejemplos de su uso). Bueno, y finalmente, hay
ejemplos que especifican reglas sintácticas específicas que asocian
patrones nombrados con ocurrencias específicas del texto fuente.
Según tengo entendido, el objetivo original que los creadores de
Gorp se
propusieron era
analizar las secuencias de datos contenidas en los archivos de informe (o archivos de registro). Considere un ejemplo simple de una aplicación específica del sistema.
Supongamos que tenemos un informe que contiene la siguiente línea:
<86> 2015-05-12T20: 57: 53.302858 + 00: 00 10.1.11.141 RealSource: "10.10.5.3"
Compongamos una plantilla de ejemplo para analizarla usando las herramientas de
Gorp :
pattern %phrase \\S+
pattern %num \\d+\n
pattern %ts %phrase
pattern %ip %phrase
extract interm {
template <%num>$eventTimeStamp(%ts) $logAgent(%ip) RealSource: "$logSrcIp(%ip)"
}
Tenga en cuenta que el bloque de asignación de plantillas incluso se omite aquí, ya que todas las plantillas necesarias ya están incluidas en la selección final. Todas las plantillas utilizadas aquí se nombran, sus contenidos se indican entre paréntesis después de su nombre. Como resultado, se creará un conjunto de datos de texto con los nombres
eventTimeStamp ,
logAgent y
logSrcIp .
Ahora escribiremos un programa simple para extraer los datos necesarios. Supongamos que la plantilla que creamos ya está contenida en un archivo llamado
extractions.xtr .
import com.salesforce.gorp.DefinitionReader; import com.salesforce.gorp.ExtractionResult; import com.salesforce.gorp.Gorp;
Otro ejemplo de una plantilla de análisis simple:
# Patterns
pattern %num \d+
pattern %hostname [a-zA-Z0-9_\-\.]+
pattern %status \w+
# Templates
@endpoint $srcHost(%hostname): $srcPort(%num)
# Extraction
extract HostDefinition {
template @endpoint $status(%status)
}
Bueno, creo que el punto está claro. Tampoco estará mal mencionar que para el método de
extracción también hay una definición con dos parámetros de entrada, el segundo de los cuales tiene un tipo lógico. Si lo establece en
verdadero , cuando se ejecute, el método iterará sobre todos los conjuntos de datos potenciales, hasta que encuentre uno adecuado (también puede reemplazar la llamada al método con
extractSafe , ya sin el segundo parámetro). El valor predeterminado es
falso , y el método puede "jurar" en la discrepancia entre los datos de entrada y la plantilla utilizada.
Observo al mismo tiempo que
Gorp.NET también introdujo una nueva implementación extendida del método de
extracción : ahora hay una versión con dos parámetros posteriores de tipo lógico. Usando una llamada abreviada a la
vista extractAllFound , establecemos ambos en true de forma predeterminada. El valor positivo del tercer parámetro nos da un alcance aún mayor para las variaciones: a partir de ahora, podemos analizar el texto con cualquier inclusión de caracteres arbitrarios en los intervalos entre las muestras deseadas, ya estructuradas (que contienen conjuntos de datos extraídos).
Entonces, ha llegado el momento de responder la pregunta: ¿qué puede ser exactamente único en esta modificación de la versión básica de
Gorp , además de la extensión del método de extracción?
El hecho es que cuando hace varios años ya creé una especie de mi propia herramienta para extraer los datos requeridos del texto (que también se basó en el procesamiento de ciertas plantillas con su propia sintaxis específica), funcionó con principios ligeramente diferentes. Su principal diferencia con el enfoque implementado en
Gorp y en todos los marcos derivados es que cada elemento de texto a extraer se estableció simplemente enumerando sus bordes izquierdo y derecho (cada uno de los cuales podría ser parte del elemento en sí o simplemente separarlo de todo el texto posterior o anterior). Al mismo tiempo, de hecho, en el caso general, la estructura del texto fuente en sí no se analizó, como es el caso en
Gorp , pero solo se seleccionaron las piezas necesarias. En cuanto al contenido del texto que está encerrado entre ellos, no podría haber sucumbido a ningún análisis estructural (podría ser un conjunto de caracteres incoherente).
¿Es posible lograr un efecto similar en
Gorp ? En su versión inicial, quizás no (corríjame si me equivoco al respecto). Si simplemente escribimos una expresión como
(. *) , Seguida inmediatamente por la máscara para especificar el borde izquierdo del siguiente elemento a buscar, luego, utilizando el cuantificador de "codicia", se capturará todo el texto posterior. Y no podemos usar clientes habituales con sintaxis "no codiciosa" en las implementaciones existentes de
Gorp .
Gorp.NET le permite sortear este problema sin problemas introduciendo dos tipos especiales de patrones:
(% all_before) y
(% all_after) . El primero de ellos, de hecho, es una alternativa a la versión "no codiciosa"
(. *) , Adecuada para compilar sus propias plantillas. En cuanto a
(% all_after) , también mira el texto fuente hasta la primera aparición de la siguiente parte del patrón descrito, pero ya se basa en el resultado de búsqueda del patrón anterior. Todo lo que se encuentre entre ellos también caerá en la subcadena extraíble del elemento actual. En cierto sentido
(% all_after) "mira hacia atrás" y
(% all_before) , por el contrario, "mira hacia adelante". Observo que un análogo único para
(% all_before) en la primera versión de
BIRMA era el borde izquierdo que faltaba en la descripción del elemento, y análogo a
(% all_after) , respectivamente, era un vacío en lugar del borde derecho. Si no se establecen ambos límites al describir el siguiente elemento, entonces el analizador obviamente captura todo el texto posterior. Sin embargo, toda esta implementación de
BIRMA ahora tiene un significado puramente histórico (puede leer un poco más al respecto
en mi informe de esa época ).
Texto ocultoLos códigos fuente nunca se han presentado en ningún lugar debido a su calidad extremadamente baja; en verdad, podrían servir como un monumento al diseño deficiente de los sistemas de software.
Veamos las características del uso de patrones de servicio
(% all_before) y
(% all_after) usando el ejemplo de la tarea de extraer datos específicos del usuario de un sitio web específico. Analizaremos el sitio de Amazon, y específicamente esta página:
https://www.amazon.com/B06-Plus-Bluetooth-Receiver-Streaming/product-reviews/B078J3GTRK/ ).
Texto ocultoSe toma un ejemplo de una tarea de prueba para la vacante de un desarrollador con especialización en análisis de datos, enviada por mi empresa, que, lamentablemente, no ha respondido a mi solución propuesta al problema. Es cierto, solo me pidieron que describiera el proceso general de la solución, sin proporcionar un algoritmo específico, y en respuesta ya intenté referirme a las plantillas de Gorp, mientras que mis propias extensiones en ese momento solo existían, como dicen, "en papel" ".
En aras de la curiosidad, me permitiré citar un fragmento de mi carta de respuesta, que, aparentemente, es la primera mención de
Gorp.NET , aunque de carácter privado.
"Para hacer que la lista anterior de expresiones regulares que utilicé para resolver este problema sea más visual, compilé una plantilla lista para usar (adjuntada a la carta), que puede usarse para extraer todos los datos necesarios aplicando mi propio desarrollo de una naturaleza más universal, solo diseñado para resolver este tipo de problema. Su código se basa en el proyecto
github.com/salesforce/gorp , y en la misma página hay una descripción general de las reglas para compilar dichas plantillas. En términos generales, tal descripción en sí misma implica la asignación de expresiones regulares concretas y la lógica de su procesamiento. El punto más difícil aquí es que para cada muestra de datos debemos describir completamente a través de los regulares la estructura completa del texto que los contiene, y no solo los elementos individuales en sí (como podría hacerse al escribir nuestro propio programa que busca secuencialmente en un ciclo, como I descrito anteriormente) ".
La tarea original era recopilar los siguientes datos de la página anterior:
- Nombre de usuario
- Calificación
- Título de revisión
- La fecha
- Texto
Bueno, ahora solo le daré una plantilla compilada por mí, que le permite completar esta tarea de manera rápida y eficiente. Creo que el significado general debería ser bastante obvio: quizás usted mismo pueda ofrecer una solución más concisa.
Texto ocultoFue en este ejemplo que, en general, depuré la funcionalidad de mis propias extensiones para Gorp (ya sin ningún objetivo de empleo, sino más bien basado en la ideología de "Prueba de concepto").
pattern %optspace ( *)
pattern %space ( +)
pattern %cap_letter [AZ]
pattern %small_letter [az]
pattern %letter (%cap_letter|%small_letter)
pattern %endofsentence (\.|\?|\!)+
pattern %delim (\.|\?|\!\,|\:|\;)
pattern %delim2 (\(|\)|\'|\")
pattern %word (%letter|\d)+
pattern %ext_word (%delim2)*%word(%delim)*(%delim2)*
pattern %text_phrase %optspace%ext_word(%space%ext_word)+
pattern %skipped_tags <([^>]+)>
pattern %sentence (%text_phrase|%skipped_tags)+(%endofsentence)?
pattern %start <div class=\"a-fixed-right-grid view-point\">
pattern %username_start <div class=\"a-profile-content\"><span class=\"a-profile-name\">
pattern %username [^\s]+
pattern %username_end </span>
pattern %user_mark_start <i data-hook=\"review-star-rating\"([^>]+)><span class=\"a-icon-alt\">
pattern %user_mark [^\s]+
pattern %user_mark_end ([^<]+)</span>
pattern %title_start data-hook=\"review-title\"([^>]+)>(%skipped_tags)*
pattern %title [^<]+
pattern %title_end </span>
pattern %span class <span class=\"[^\"]*\">
pattern %date_start <span data-hook="review-date"([^>]+)>
pattern %date ([^<]+)
pattern %date_end </span>
pattern %content_start <span data-hook=\"review-body\"([^>]+)>(%skipped_tags)*
pattern %content0 (%sentence)+
pattern %content (%all_after)
pattern %content_end </span>
template @extractUsernameStart (%all_before)%username_start
template @extractUsername $username(%username)%username_end
template @extractUserMarkStart (%all_before)%user_mark_start
template @extractUserMark $user_mark(%user_mark)%user_mark_end
template @extractTitleStart (%all_before)%title_start
template @extractTitle $title(%title)%title_end
template @extractDateStart (%all_before)%date_start
template @extractDate $date(%date)%date_end
template @extractContentStart (%all_before)%content_start
template @extractContent $content(%content)%content_end
extract ToCEntry {
template @extractUsernameStart@extractUsername@extractUserMarkStart@extractUserMark@extractTitleStart@extractTitle@extractDateStart@extractDate@extractContentStart@extractContent
}
Eso es probablemente todo por hoy. Sobre las herramientas de terceros que he implementado, en las que este marco ya ha estado completamente involucrado, puedo decirte en otro momento.