lunes, 28 de julio de 2025

Textos. Procedimientos

 Variables vg que no lo son


Inicio con esta entrada el abordaje de mejoras y de alternativas de respuesta a los planteamientos de automatización basados en el uso de OOo Basic como herramienta, de los que he estado tratando en esta subsección (Procedimientos), pero también en la subsección Automatización, ambas de la sección Textos.


En realidad son varias las mejorar y las alternativas posibles, pero empezaré por una tan sencilla como necesaria para resolver un problema presente en el procedimiento desarrollado hasta este momento. Me refiero a cómo tratar esas vg no son tales y hasta ahora han quedado sin respuesta.

Algunas variables asimiladas e identificadas como  gramaticalmente condicionadas realmente no se rigen por ningún criterio de concordancia, por lo que en sentido estricto no estarían correctamente calificadas dentro de este subtipo. De hecho no funcionan bien usando el procedimiento creado para la automatización de las vg, como habrás podido comprobar en el [documento resultante] del DocAp anterior. Sin embargo son expresiones de un recurso de referenciación del sujeto muy usado en los informes del que no nos conviene prescindir. Me refiero a la reiteración del nombre propio del alumno como forma de personalización del informe.

Este recurso es de uso muy frecuente, llegando a ser el dominante en algunas propuestas de automatización del informe, especialmente cuando el uso de OOo Basic es limitado, como sucede en las propuestas primitivas de automatización textual. Realmente es un recurso muy eficaz como forma de identificar al sujeto del quien se realiza el informe, aunque si lo usamos en exceso llega a resultar artificioso y hasta molesto. Por ello, en propuestas más avanzadas de automatización, se incorporar otras expresiones con funciones equivalentes que hacen que el texto generado automáticamente esté más próximo al creado manualmente (1).

Sin embargo, el dominio de las vg y la imposición de procedimientos de automatización ajustados a sus características (2) en la propuesta actual deja sin respuesta a lo que en formulaciones anteriores era la fórmula básica de personalización, quedando ahora sin contenido cuando se cambia el nombre del alumno del documento-base al uso del DocAp, lo que resulta ser, por razones obvias, lo más frecuente (3).

Para resolver este fallo de funcionamiento, podemos hacer una excepción al procedimiento actual y volver a soluciones anteriores; también podemos buscar una solución que se mantenga dentro de la lógica de nuestra propuesta actual. Lo que no es aceptable es no dar solución al problema.

En ambos casos deberemos modificar la asignación de la categoría vg a esta variable a fin de identificarla correctamente y poder darle el tratamiento que precisa. Esta variable no se puede confundir con la vi-condicionante, ya que es una variable condicionada directamente por ella, compartiendo con el resto de las vg esa dependencia. En consecuencia no puede ser tratada como vi a efectos de entrada de datos, pero hemos comprobado que tampoco puede tratada del modo en que lo son las vg (4).

Una posible solución pasa por:
  • Identificarla como una categoría diferente (vn) o variable-nombre. Esto supone modificar el script Standard | CrearMatrizBase | MatrizBase, concretamente el segmento...
'Identificación de categorías de los segmentos textuales (mTipos())
For i = LBound(mSegmentos()) To UBound(mSegmentos())
If mSegmentos(i) = "" Then
mTipos(i) = "sl"
ElseIf mSegmentos(i) = "," or mSegmentos(i) = "."  or mSegmentos(i) = ";" Then
mTipos(i) = "sp"
Else
mTipos(i) = InputBox(mSegmentos(i),"Categorización de los segmentos textuales","tf-vi-vg-vn")
End If
Next

 ... para que se incorpore esta nueva categoría como identificador.


  • Modificar el script NuevoDoc | NuevoInfo | NuevoInforme incorporando el siguiente bucle...
'Especificamos el contenido de las vn según el nombre del alumno
For i = LBound(mCateg()) To UBound (mCateg())
If mCateg(i) = "vn" Then
mTextos(i) = AlNuevo
End If
Next

 ... para que se recoja el nombre del alumno objeto de informe en la posición en que se encuentre la variable vn identifica en el proceso de categorización realizado con el script MatrizBase.

Te invito a que realices esas modificaciones en ambos script y compruebes si funciona la modificación que propongo. Para comprobarlo puedes desarrollar el proceso desde cero, borrando las hojas MatrizBase y CondicGen y activando el script MatrizBase una vez modificado (5).


NOTAS

(1) Este objetivo es uno de los responsables de la incorporación de expresiones como "el alumno", "el niño"... al conjunto de recursos de composición de los textos automatizados, generando la necesidad de dar un tratamiento específico a las que he llamado vg.
(2) Tratamiento de la dicotomía masculino-femenino para la concordancia de género, por ejemplo.
(3) Como puedes comprobar en el informe resultante de la aplicación del DocAp, según señalé anteriormente en esta entrada.
(4) No cabe incluirla como elemento de la BDGenero
(5) También puedes modificar directamente el dato de la celda B17 de MatrizBase, sustituyendo vg por vn. Esto hace que sea innecesario modificar el script MatrizBase, pero te recomiendo que hagas esa modificación de todos modos, ya que sólo así se corrige realmente el error.

domingo, 27 de julio de 2025

Textos. Procedimientos

Segunda fase del procedimiento: el DocAp


Hasta este momento he estado trabajando sobre el texto-base, desarrollando los procedimientos que facilitan su estructuración en segmentos, la identificación de las categorías funcionales a las que pertenecen estos segmentos y la construcción de un cuestionario que nos ayude en la entrada de datos. Con todo ello resuelto (1), corresponde ahora formular el script-DocAp, esto es, el que nos permite sacar provecho del trabajo realizado y automatizar la elaboración del documento.


Si el planteamiento del proceso en dos fases es definitorio del modelo de automatización que ensayamos en este ejemplo, el script que voy a presentar en esta entrada es su culminación. Funcionalmente cumple el papel de los script que sirvieron de soporte a un DocAp, de ahí que mantenga para él esa denominación.


Como DocAp que disponible desde el cmd que se ve en la imagen, en la hoja inicial del soporte-Calc (TextoBase), que activa el script NuevoInforme que muestro a continuación.

Sub NuevoInforme

'Acceso a la hoja con los datos (MatrizBase)

Dim oHojaDatos As Object
oHojaDatos = ThisComponent.getSheets().getByName("MatrizBase")

'Cargo datos en matrices y variables de trabajo
Dim mTextos() As String, mCateg() As String, mPreg() As String
Dim i As Integer, n As Integer
Dim oCelda As Object
Dim Conten As String

'Calculo el número de elementos de la matriz-base
For i = 0 To 100
oCelda =  oHojaDatos.getCellRangeByName("B" & i+1)
Conten = oCelda.getString()
If Conten = "" Then
n = i+1
Exit For
End If
Next

'Dimensiono las matrices
ReDim mTextos(n)
ReDim mCateg(n)
ReDim mPreg(n)

'Capturo el contenido de las columnas de datos
For i = LBound(mTextos()) To UBound (mTextos())
oCelda = oHojaDatos.getCellRangeByName( "A" & i+1 )
mTextos(i) = oCelda.getString()
mTextos(i) = Trim(mTextos(i))
Next

For i = LBound(mCateg()) To UBound (mCateg())
oCelda = oHojaDatos.getCellRangeByName( "B" & i+1 )
mCateg(i) = oCelda.getString()
Next

For i = LBound(mPreg()) To UBound (mPreg())
oCelda = oHojaDatos.getCellRangeByName( "C" & i+1 )
mPreg(i) = oCelda.getString()
Next

'Modifico el contenido de las vi del texto a generar
For i = LBound(mTextos()) To UBound (mTextos())
If mCateg(i) = "vi" Then
mTextos(i) = InputBox (mPreg(i),"Datos actuales",mTextos(i))
End If
Next

'Capturo la posición de la vi-condición de los datos vg
Dim post As String, pos As Integer
Dim genOr As String
oHojaDatos = ThisComponent.getSheets().getByName("CondicGen")
oCelda = oHojaDatos.getCellRangeByName("B1")
post = oCelda.getString()
pos = CInt(post)

'Capturo el género de la vi-condición original
oCelda = oHojaDatos.getCellRangeByName("B2")
genOr = oCelda.getString()

'Establezco el genero del nuevo alumno en base a la posición en la mTextos() de la vi
Dim AlNuevo As String
AlNuevo = mTextos(pos)

'Busco el género del nuevo alumno en la BDNombres 
Dim GenAlNuevo As String
GenAlNuevo = GeneroNombre(AlNuevo)

'Comparo el género de ambos nombres
Dim ComparaGen As Boolean
If genOr = GenAlNuevo Then
ComparaGen = True
Else
ComparaGen = False
End If

'En caso de discrepancia de género modifico los datos de las vg
Dim NuevoTermino As String
If ComparaGen = False Then
For i = LBound(mCateg()) To UBound (mCateg())
If mCateg(i) = "vg" Then
NuevoTermino = Genero(mTextos(i))
mTextos(i) = NuevoTermino
End If
Next
End If

'Recompongo el texto a partir de la matriz mTextos()
Dim NuevoTexto As String

For i = LBound(mTextos()) To UBound (mTextos())
If i = 0 Then
NuevoTexto = mTextos(i)
Else
If mCateg(i) = "sl" Then
NuevoTexto = (NuevoTexto & Chr(13) & Chr(13))
ElseIf mCateg(i) = "sp" Then
NuevoTexto = (NuevoTexto & mTextos(i))
Else
NuevoTexto = (NuevoTexto & " " & mTextos(i))
End If
End If
Next

'Escribo el texto recompuesto en un nuevo documento Writer
Dim sRuta As String
Dim mArg()
Dim oDoc As Object, oDocum As Object

sRuta = "private:factory/swriter"
oDoc = StarDesktop.loadComponentFromURL(sRuta, "_default", 0, mArg() )
oDocum= oDoc.Text
oDocum.insertString(oDocum.getEnd(),NuevoTexto, False)

End Sub

Como en otras ocasiones, los comentario del script facilitan su comprensión y ahorran ahora trabajo de explicación. Sólo es necesario insistir en una cuestión: se da por supuesto que el acceso a las bases de datos complementarias quedan bien resueltas mediante el recurso a dos funciones que aquí no se exponen (sí en el documento que se anexa), pero esto sólo es cierto si estas bases de datos son actualizadas "manualmente" por el profesional. No hay nada en el código que garantice que esto es así.

Esta es una de las cuestiones pendientes. No es la única.

Documentos. 

Los enlaces que te proporciono a continuación para que los descargues requieren que crees una carpeta en tu Escritorio (Textos) y que modifique la dirección de archivos que se plantean en los script principales por la dirección que se ajuste a tus archivos. Como tienes que realizar estos cambios, puedes aprovechar para crear también tu estructura de directorio, incluyendo la unidad de trabajo o el directorio de la unidad C:

Ya están creadas las hojas auxiliares en el documento Calc, con lo que sólo te resta activar el cmd de la hoja principal para crear un nuevo informe. 

Aunque el listado de nombres es amplio, te recomiendo que accedas a la BDNombres y te cerciores de que el que tiene tu alumno (o alumna) ya está registrado (no hace falta hacer lo mismo con la BDGenero). En caso contrario, debes añadirlo a la lista (nombre y género). Si deseas trabajar desde el principio, deberás borrar antes las hojas MatrizBase y CondicGen; pero sólo si deseas trabajar con el script que crea ambas y los procesos que genera. Recuerda que ese script debe ser activado directamente desde el IDE y que está en la biblioteca Standard y en el módulo CrearMatrizBase.

NOTA (1) En realidad he aparcado unas cuantas cuestiones para otro momento; lo haré de nuevo ahora, ya que es necesario para avanzar en el desarrollo de la solución.

sábado, 26 de julio de 2025

Textos. Automatización

Variables causalmente condicionadas


Personalmente considero estas variables como las de mayor interés como profesional, pero también las de mayor dificultad para ser automatizadas, lo que no implica que no puedan ser abordadas mediante algoritmos, pero exigen diferentes tratamientos, dada su diversidad y complejidad.



Debido a ello, recurrir a procedimientos simples de automatización resulta insatisfactorio, aunque el más simple de todos ellos, el que he denominado vi, resulta ser el más útil en la práctica. Se puede pensar que recurrir a esta alternativa implica, en realidad, renunciar a  tratar las vc como tales. No falta razón para ello, pero no en todos los casos es un simple truco claudicante, como veremos a continuación.

Tomando como referencia [el texto que nos sirve de referencia], se identifican en él las siguientes variables condicionalmente determinadas (vc)

Antonio#es un alumno#con NEE derivadas de#discapacidad auditiva#que requiere apoyos de#Audición y Lenguaje y de Pedagogía Terapéutica#.#

Identificamos, pues, tres vc entre las que diferenciamos al menos dos subtipos en cuanto al tratamientos posible (diferenciadas por el color), pero también dos subtipos por la naturaleza de la causalidad. Empezaré por esta segunda cuestión.

Siendo meramente descriptivo y ciñéndome únicamente al texto que tenemos delante, NEE discapacidad auditiva comparten ser categorizaciones del sujeto y sus condiciones personales, aunque incluso compartiendo esto, se diferencian tanto en el posible tratamiento (tema aun pendiente de aclarar), como en la naturaleza de esa categorización: NEE hace referencia a una categoría educativa (de base teórica, pero también normativa), mientras que discapacidad auditiva remite a una categorización clínica, que el educador recibe del ámbito clínico-sanitario y después reinterpreta en función de implicaciones educativas. 

La necesidad o no de apoyos, y de qué tipo de apoyos (nuestra tercera variable: Audición y Lenguaje y de Pedagogía Terapéutica), es, a su vez, una implicación casual que deriva de datos que en ningún momentos se muestran en el texto. Esto no sucede en la relación que se observa en el propio texto entre la vi-condicionante de las vg y éstas. 

Es por ello que transformar las vc en vi no es únicamente una salida ante las dificultades que supone automatizarlas. También responde a una realidad: realizar inferencias sin datos no es inviable.

Veamos ahora en qué consiste la diferencia primera (la de tratamiento). 

El segmento vc con NEE derivadas de está compuesto realmente des dos subsegmentos con NEE y derivadas de, aunque se presentan como un único segmento al descontar ya la identidad tipológica de ambos. Dado que derivadas de es claramente un segmento tf, es fácil adivinar que, por el principio de simplificación, con NEE también se va a considerar tf; pero ¿por qué?.

Si tengo en cuenta la naturaleza del documento en que estoy trabajando, esto es, si tomo en consideración en contexto o marco en el que se produce el intento de automatización, tendré presente que no cabe otra posibilidad que la que se señada en el texto: que el alumno presente NEE. De no ser así, no tendría sentido elaborar el informe (1), por lo que con NEE es consustancial a la naturaleza del texto que sirve de contexto al segmento, siendo entonces posible asimilarlo funcionalmente a un tf

Dado que se observan dos tf sucesivos, también por simplificación del procedimiento es conveniente tratarlos como una unidad. De ahí que con NEE derivadas de se presente como un único segmento tf.

Este razonamiento no es pertinente para el caso del segmento discapacidad auditiva, ya que en realidad es una de las diferentes posibilidades causales/relacionales de NEE, siendo posible identificar un conjunto suficientemente amplio de opciones: tantas como las que recoge la normativa y, posiblemente, recuerde la propia convocatoria.

El texto del segmento discapacidad auditiva puede ser objeto de procedimientos algorítmicos específicos de determinación causal, así como de discusión teórica respecto a la naturaleza de esa causación. Pero esto no añade claridad ni facilita la resolución funcional del problema que ahora enfrentamos: automatizar la identificación de la tipología que plantea este segmento. 

Dado que no contamos con vi informativas en el texto-base que nos permitan desarrollar procedimientos decisionales algorítmicos, tenemos dos opciones: obtener el dato de un soporte que sí cuente con esos datos y desarrolle el algoritmo decisional, o recurrir a un procedimiento más simple: tratar el segmento como vi, esto es, tratarlo como un dato y pedírselo al profesional que elabora el informe sin entrar en cómo él lo consigue.

Finalmente el segmento Audición y Lenguaje y de Pedagogía Terapéutica comparte en cierto modo características propias de cada uno de los dos anteriores, aunque funcionalmente, en el texto-base, se acerca más al segundo de los tres. Tiene similitud con el primero en cuanto no sería pertinente en el contexto del informe su total ausencia (que es una de las diversas posibilidades de respuesta), pero saber esto no aporta la respuesta concreta entro de las tres posibles que restan: únicamente Audición y Lenguaje, sólo Pedagogía Terapéutica o ambos apoyos. Evidentemente faltan aquí también los datos vi necesarios para optar por una respuesta u otra, así que también ahora caben  las mismas posibilidades que planteamos respecto al segundo segmento, pero hay una diferencia respecto a aquel: ahora es posible ofrecer en el algoritmo una solución que ofrezca cuanto menos las alternativas para facilitar la respuesta del profesional; omitir esta formulación es una de las opciones, pero no la única. Al hacerlo y presentar únicamente el procedimiento básico de las vi optamos por una simplificación del propio procedimiento, priorizando la simplicidad también en la formulación del algoritmo sobre su funcionalidad como DocAp.

Apuesto por esta solución, ya que también en esto consiste automatizar el procedimiento de elaboración del informe.


NOTA (1) En caso contrario simplemente no es pertinente hacer ningún informe. Otra cosa es que la convocatoria no se limite a la condición de NEE; por ejemplo, que se dirija también al alumnado con NEAE por AC. En este caso los segmentos (con NEE derivadas de# y discapacidad auditiva#) deberán ser tratados de forma diferente. También podemos resolver esta cuestión creando una versión específica de informe-becas para ese otro alumnado, eludiendo estas complicaciones, aunque generalizar esta opción no es una buena solución a la larga.


Textos. Procedimientos

Tratamiento de las v-input


Concluyo con esta entrada, en la práctica y en lo esencial, la fase primera del desarrollo de este modelo de automatización de textos, aunque quedan algunas cuestiones que en estos momentos implícitamente estoy considerando como accesorios, aunque posiblemente no lo sean tanto. Desde esta perspectiva más funcional que otra cosa, se debe "rematar la faena" hablando del tratamiento de las llamadas variables-input (vi).


Dado
que 
[algo sabemos ya de ellas] no me voy a detener aquí en lo ya explicado, y lo que resta por explicar tendrá que esperar al momento oportuno, así que me limitaré a exponer el modo en que genero la base para el cuestionario sobre las vi sobre la matriz (mCuestionario())...

For i = LBound(mSegmentos()) To UBound (mSegmentos())
If mTipos(i) = "vi" Then
mCuestionario(i) = InputBox (mSegmentos(i) & Chr(13),"Cuestionario para facilitar la entrada de datos")
End If
Next

... y la dejamos a disposición para ser usado posteriormente...

For i = LBound(mCuestionario()) To UBound (mCuestionario())
oTexto = oHojaMatrizBase.getCellRangeByName( "C" & i+1 )
oTexto.setString(mCuestionario(i))
Next

Este tercer componente de la hoja MatrizBase nos permitirá desarrollar la segunda fase de esta propuesta de automatización, la cual tiene ya más similitud con un DocAp basado en un gestor Calc, del cual precisamente se diferencia a consecuencia del modo en que operamos con ese cuestionario (1). Pero como esta entrada es también final de fase, corresponde exponer en ella el script que hemos ido trabajando por partes en esta y en entradas anteriores.

Sub MatrizBase

'Acceder a la hoja TextoBase
Dim oHoja As Object
oHoja = ThisComponent.getCurrentController.getActiveSheet()
'... a la celda A1 que contiene el texto
Dim oTexto As Object
oTexto = oHoja.getCellRangeByName( "A1" )
'... y al contenidos de A1
Dim sTexto As String
sTexto = oTexto.getString()

'Dividimos el texto en segmentos mediante la función Split()
Dim sSepara As String
Dim mSegmentos() As String
Dim SegTxt As String
Dim i As Integer
Dim n As Integer

sSepara = "#"
mSegmentos = Split(sTexto(),sSepara)

'Eliminamos espacios mediante la función Trim()
For i = LBound(mSegmentos()) To UBound(mSegmentos())
SegTxt = mSegmentos(i)
mSegmentos(i) = Trim(SegTxt)
n = i+1 'Obtenemos la longitud de la matriz mSegmentos()
Next

'Calificamos los segmentos textuales
'tf -> texto fijo
'vi -> variable-input y variable-condicionada
'vg -> variable-gramatical
'sp -> signos de puntuación aislados
'sl -> segmento vacío

'Matrices complementarias:
' mTipos() -> para categorización de los segmentos
' mCuestionario -> para interface con usuario sobre vi
Dim mTipos(n) As String, mCuestionario(n) As String

'Identificación de categorías de los segmentos textuales (mTipos())
For i = LBound(mSegmentos()) To UBound(mSegmentos())
If mSegmentos(i) = "" Then
mTipos(i) = "sl"
ElseIf mSegmentos(i) = "," or mSegmentos(i) = "."  or mSegmentos(i) = ";" Then
mTipos(i) = "sp"
Else
mTipos(i) = InputBox(mSegmentos(i),"Categorización de los segmentos textuales","tf-vi-vg-sl-sp")
End If
Next

'Cuestionario para interface respecto a vi (mCuestionario())
For i = LBound(mSegmentos()) To UBound (mSegmentos())
If mTipos(i) = "vi" Then
mCuestionario(i) = InputBox (mSegmentos(i) & Chr(13),"Cuestionario para facilitar la entrada de datos")
End If
Next

'Creamos la hoja MatrizBase
Dim oHojas As Object
oHojas = ThisComponent.getSheets()
oHojas.insertNewByName("MatrizBase", 2)

Dim oHojaMatrizBase As Object
oHojaMatrizBase = ThisComponent.getSheets().getByName("MatrizBase")

' Copiamos la matriz mSegmentos() en la columna A
For i = LBound(mSegmentos()) To UBound (mSegmentos())
oTextoMatriz = oHojaMatrizBase.getCellRangeByName( "A" & i+1 )
oTextoMatriz.setString(mSegmentos(i))
Next

'Copiamos la matriz mTipos() en la columna B
For i = LBound(mTipos()) To UBound (mTipos())
oTextoMatriz = oHojaMatrizBase.getCellRangeByName( "B" & i+1 )
oTextoMatriz.setString(mTipos(i))
Next

'Copiamos la matriz mCuestionario() en la columna C
For i = LBound(mCuestionario()) To UBound (mCuestionario())
oTexto = oHojaMatrizBase.getCellRangeByName( "C" & i+1 )
oTexto.setString(mCuestionario(i))
Next

'Identificación de la vi condicionante de las vg
Dim posCond As Integer, valor As Integer
Dim viCond As String, conGen As String

'Valor de posición de la variable vi condicionante en la matriz mSegmentos() -> variable posCond
For i = LBound(mSegmentos()) To UBound (mSegmentos())
If mTipos(i) = "vi" Then
valor = MsgBox(mSegmentos(i),36,"VI condicionante de las vg")
If valor = 6 Then
posCond = i
Exit For
End If
End If
Next

'Contenido de la vi condicionante (viCond)
viCond = mSegmentos(posCond)

'Identificación del género consultando a la bdNombres (conGen)
conGen = CondGen(viCond)

'Creación de la hoja CondicGen
oHojas.insertNewByName("CondicGen", 3)

'Posicionamiento en la hoja CondicGen
Dim oHojaCond As Object
oHojaCond = ThisComponent.getSheets().getByName("CondicGen")

'Copia de los datos posición y género de la vi condicionante
Dim oTxtCond As Object

oTxtCond = oHojaCond.getCellRangeByName( "A1" )
oTxtCond.setString("Posición")

oTxtCond = oHojaCond.getCellRangeByName( "B1" )
oTxtCond.setString(posCond)

oTxtCond = oHojaCond.getCellRangeByName( "A2" )
oTxtCond.setString("Género")

oTxtCond = oHojaCond.getCellRangeByName( "B2" )
oTxtCond.setString(conGen)

End Sub

En el script se pueden identificar esas partes gracias a los comentarios, lo que nos ahorra dar más explicaciones de las necesarias.

 

NOTA (1) Veremos en su momento, porque aquí no trataremos sobre el desarrollo de esa segunda fase, que se trabaja también en base a un bucle y con recursos simples de input (InputBox() asociados a ciclos  que recorren las matrices que ahora guardamos como datos en MatrizBase