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.