lunes, 30 de septiembre de 2024

Funciones. Matrices.

Límite inferior y superior de una matriz

Posiblemente conocemos los valores numéricos que marcan las posiciones inicial y final de una matriz, bien por establecer su dimensión (número de elementos) en la declaración de la matriz, bien por otros motivos, pero no siempre es así... ni necesitamos que así sea.


Bien por desconocimiento, bien por asegurarnos de no cometer un error, dos funciones Built-In disponibles para trabajar con matrices nos resuelven el problema de conocer los valores de posición inicial y final de una matriz. Estas dos funciones son LBound() y UBound().

Ambas funciones reciben como único parámetro la matriz sobre la que trabajamos y devuelven un valor numérico (Integer) que identifica la posición inicial (LBound()) y final de la matriz (UBound()).

Cierto que la posición inicial es invariablemente la posición 0, ya que esa es la posición con la que se inician todas las matrices en OOo Basic (1) salvo que indiquemos los contrario, con lo que LBound() nos ofrece poca información novedosa, pero UBound() sí resulta de gran interés, dado que no siempre sabemos cuanto elementos tiene una matriz y, en consecuencia, no sabemos cual es el valor de posición del último. Ya a la inversa: gracias a UBound() podemos saber cuántos elementos componen una matriz, ya que es suficiente con sumar +1 al valor que nos devuelve para saberlo. Un ejemplo sencillo:

Sub Longmatriz

Dim mDiaSem() As String
Dim iPosIni As Integer, iPosFin As Integer, iNumElem As Integer

mDiaSem() = Array("lunes", "martes", "miércoles", "jueves", "viernes", "sábado","domingo")

iPosIni = LBound(mDiaSem())
iPosFin = UBound(mDiaSem())
iNumElem = iPosFin + 1

MsgBox "Posición del primer elemento de la matriz: " & iPosIni
MsgBox "Posición del último elemento de la matriz: " & iPosFin
MsgBox "Número de elementos de la matriz: " & iNumElem

End Sub

GraciasLBound(mDiaSem()) confirmamos algo que sabemos por definición: que el valor de posición del primer elemento de la matriz mDiaSem()  es 0 y gracias a UBound(mDiaSem()) que el valor de la posición final es 6. Es suficiente con realizar una sencilla operación (iNumElem = iPosFin + 1) para conocer el número de elementos que la componen (7).

El uso de ambas funciones tiene especial interés cuando necesitamos recorrer el contenido de una matriz mediante un bucle. En este caso (también para asegurarnos y evitar errores), puede ser más sencillo asignar los valores devueltos por ambas funciones como iterable del ciclo. Por ejemplo:

For i = LBound(mDiaSem()) To UBound(mDiaSem())
MsgBox ("Dia " & i+1 & " de la semana: " & mDiaSem(i))
Next

Ambas funciones sirven respectivamente para marcar el valor de inicio y de finalización del bucle For (For i = LBound(mDiaSem()) To UBound(mDiaSem())) en función de los valores que devuelven respecto a la matriz mDiaSem(), con lo que no cabe posibilidad de error (2).

NOTAS

(1) Salvo que indiquemos lo contrario mediante la instrucción Option Base declarada al inicio del módulo y fuera del cuerpo de los script: Option base 1 hace que las matrices inicien en la posición 1. Aunque es una posibilidad, en la práctica no es frecuente hacer uso de ella.
(2) Este uso de ambas funciones es muy frecuente en el trabajo con bucles sobre matrices, así que es común encontrarlo en el código de los script y funciones. La principal razón de ello es que impide cometer errores de infradimensionar o sobredimensionar el ciclo respecto al número de elementos de la matriz.

Funciones. Matrices.

Introducción de datos

Para introducir datos directamente en una matriz unidimensional (una lista) disponemos de la conocida opción de asignación directa (mMatriz(0) = "lunes"), pero también contamos con una función muy fácil de usar que nos permite introducir directamente todos los datos de la matriz: la función Array() (1)


Esta función es de tipo Built-In (incorporada en el lenguaje) lo que significa que la podemos usar directamente, pero también que no podemos acceder a su código. Lo que sí podemos es conocer su sintaxis formal y acceder al Return que devuelve.

La función Array() recibe un único parámetro: la colección de datos que introducimos separados por comas, y nos devuelve una matriz unidimensional o lista en la matriz previamente declarada con que la asociemos en la instrucción formulada (2)

Utilizando la lista de días de la semana como ejemplo, ilustro a continuación el uso de la función Array():

Sub DiasSemana

Dim DiaSem() As String

DiaSem = Array("lunes", "martes", "miércoles", "jueves", "viernes", "sábado", "domingo")

MsgBox DiaSem(0) (3)

End Sub 


NOTAS

(1) Sobre esta función ya hablamos en una [entrada anterior]
(2) Una de las ventajas de Array() es que no es necesario dimensionar la matriz de destino, ya que ésta asume tantos elementos como le pasemos mediante la función.
(3) La única función de esta instrucción es demostrar que la matriz DiaSem() contiene los elementos introducidos mediante Array(). En este caso nos devolverá lunes. Si quisiéremos verlos todos podríamos optar por varias soluciones; una de ellas crear un bucle que recorra el contenido de la matriz, elemento a elemento.

Funciones. textos

Buscar y reemplazar (b)

Además de la función Replace() vista en la [entrada anterior], para la misma función también contamos con una segunda función, desarrollada ésta por los colaboradores de [wiki.open-office.es]: la función ReplaceAll() (reemplazar todo), a la que dedicaré esta entrada por el interés que tiene en si misma y para comparar con la solución anterior. 


Por eso de no perder el tiempo, paso a mostrar la sintaxis de la función:

Function ReplaceAll(cCadena As String, cBusca As String, optional cReemplaza As String) As String

  If IsMissing( cReemplaza ) Then cReemplaza = ""
  ReplaceAll = Join( Split( cCadena, cBusca ), cReemplaza )

End Function

Lo primero que te llamará la atención es lo breve su extensión frente a la de Replace(), algo que ilustras la diversidad de opciones que tenemos a nuestro alcance para dar solución, la misma solución, al mismo problema.

Lo segundo a destacar es la al menos aparente sencillez estructural de esta función frente a la anterior: en ReplaceAll() se simplifica el código eliminando el bucle y manteniendo únicamente un condicional. Cierto que la sensación de simplificación se ve acentuada por la formulación simplificada del condicional (If IsMissing( cReemplaza ) Then cReemplaza = "") frente a la formulación canónica en OOo Basic (1); también el modo en que se expresa el Return (ReplaceAll = Join( Split( cCadena, cBusca ), cReemplaza )), que ahorra la declaración de variables privadas en la función.

La función ReplaceAll() recibe tres parámetros, dos de ello obligados y el tercero opcional, y todo ellos de tipo String.  Los dos obligatorios hacen referencia a la cadena sobre la que se trabaja (cCadena) y la subcadena (palabra) que se pretende sustituir (cBusca); la opcional traslada a la función la subcadena (palabra) sustitutoria (cReemplaza). Precisamente para gestionar la ausencia de este parámetro se define el condicional If que incluye la función IsMissing() que devuelve el valor cadena vacía como alternativa para dicho parámetro (cReemplaza = "") (2)

El núcleo de la función está, no obstante, en la compleja expresión que se asocia al Return, ya que se realiza directamente, incluye la llamada a dos funciones Built-In vistas [aquí] y se presentan anidadas: Join(Split(cCadena, cBusca ), cReemplaza).

En esta expresión, la función Join() recibe como primer parámetro el valor que devuelve la función Split() (esto es, la matriz de las palabras que contiene la cadena-base, que constituye su primer parámetro y ha sido pasada como primer parámetro la función-madre) y como segundo (String de separación), el valor de la palabra sustitutoria.

Analizando el proceso de dentro a fuera, Split() devuelve una matriz compuesta por dos elementos: la subcadena que precede a la palabra que constituye su segundo parámetro (esto es, la palabra buscada) (La) y la subcadena que la sigue (de la pradera), omitiendo (puesto que sirve de separador) la palabra a sustituir (casa). 

Por su parte, la función Join() une los elementos de esa lista o matriz que le entrega la función Split() (que, como dijimos, constituye su primer parámetro, o sea, la matriz de subcadenas a unir), utilizando como elemento de unión precisamente la palabra que queremos reemplace a la que deseamos sustituir. De este modo, la palabra-enlace de la función Join() se sitúa entre las dos subcadenas que obtuvimos mediante la función Split(), resultando de ello un proceso de sustitución de una palabra-enlace (segundo parámetro de Split()) por otra palabra de enlace (segundo parámetro de Join()) (3). Todo esto se resume en que la función ReplaceAll() devuelve una cadena en la que una palabra es sustituida por otra, que es lo que se pretende con ella.

NOTA

(1) Sobre esta cuestión ver [esta entrada]
(2) En caso de que no pasemos una subcadena mediante el parámetro cReemplaza, su lugar será ocupado por una subcadena vacía. Personalmente no me gusta el efecto que deriva de ello, aunque evidentemente es una de las soluciones posibles.
(3) Entiendo que esta explicación comporta cierta dificultad, pero resulta necesaria para comprender el modo en que se emplean ambas funciones y el efecto que produce su uso. Obsérvese que, según vimos [en su momento], el segundo parámetro de ambas funciones tenía un significado funcional diferente al que se usa en la función RemoveAll(): aunque son fundamentales, no dejan de ser accesorios, pero en RemoveAll() resultan fundamentales (su uso combinado es el que facilita la sustitución de una palabra por otra). Esto da idea de las posibilidades que presentan ambas funciones, más allá de lo aparente.


domingo, 29 de septiembre de 2024

Funciones. Textos.

Buscar y reemplazar (a)

Los procesadores de texto incluyen dos funcionalidades que resultan de mucha utilidad para analizar el contenido de un texto en términos cuantitativos y para modificar dicho contenido. Me refiero a Buscar y Buscar y reemplazar (1). En OOo Basic podemos desarrollar la primera funcionalidad haciendo uso de las [funciones Left()Right() y Mid()], pero no disponemos de funciones Built-In para reemplazar subcadenas dentro de un texto.


La forma de superar esta carencia es utilizar funciones construidas por la comunidad de usuarios, algo que, por suerte, está a nuestro alcance: tanto en [wiki.openoffice.org] como en [wiki.open-office.es] podemos encontrar funciones que cumplen con este propósito.

Vamos a empezar por la primera (Replace()), disponible en [wiki.openoffice.org], que tiene por objetivo facilitar la búsqueda y el reemplazo de una subcadena, pero como limitación, que sólo lo hace con la primera aparición de dicha subcadena. Reproduzco primero su sintaxis y la explico a continuación:

Function Replace(Source As String, Search As String, NewPart As String)

  Dim Result As String
  Dim StartPos As Long
  Dim CurrentPos As Long
 
  Result = ""
  StartPos = 1
  CurrentPos = 1
 
  If Search = "" Then
    Result = Source
  Else 
    Do While CurrentPos <> 0
      CurrentPos = InStr(StartPos, Source, Search)
      If CurrentPos <> 0 Then
        Result = Result + Mid(Source, StartPos, (CurrentPos - StartPos))
        Result = Result + NewPart
        StartPos = CurrentPos + Len(Search)
      Else
        Result = Result + Mid(Source, StartPos, Len(Source))
      End If                ' Position <> 0
    Loop 
  End If 
 
  Replace = Result
  
End Function

La función Replace() (reemplazar) recibe tres parámetros: la cadena sobre la que trabaja (Source, fuente), la palabra que deseamos reemplazar (Search, buscar) y la palabra con la que deseamos reemplazar a la que buscamos (NewPart); como vemos, los tres de tipo String.

Tiene, además, tres variables privadas, necesarias para el funcionamiento de la función (Result,StartPos CurrentPos), la primera como variable a la que referenciar el resultado de la función, obviamente de tipo String, y las otras dos de tipo numérico: StartPos (iniciar desde la posición...) y CurrentPos (posición actual) (2). Estas variables se inicializan a continuación con valores mínimos.

Lo primero que hace la función es controlar un posible error: detectar si la palabra buscada (Search) es en realidad una cadena (subcadena) vacía; en ese caso, mediante un condicional (If Search = "" Then), nos devolverá la cadena originaria como respuesta (Result = Source); en caso contrario (Else) se desarrolla lo nuclear de la función.

Esta parte, que es la fundamental de Replace(), contiene un bucle (Do While) que contiene a su vez un segundo condicional (If...End If), que parten ambas de un valor <>0 para la variable local CurrentPos (Do While CurrentPos <> 0 -> If CurrentPos <> 0 Then), condición que inicialmente se cumple, ya que CurrentPos se a inicializado con valor 1 (CurrentPos = 1).

Dentro de esta estructura se llama o hace uso de funciones Built-In (InStr(), Mid() y Len()) que destaco en negrita para facilitar su localización en el código (3).

La primera de la que hacemos uso mientras se mantiene la condición antes indicada (Do While CurrentPos <> 0), es la función InStr(), que recibe tres parámetros y queda modifica el valor inicial de CurrentPos (CurrentPos = InStr(StartPos, Source, Search)). Esos parámetros son, respectivamente, la variable privada StartPos (posición desde la que iniciar la búsqueda, cuyo valor se ha establecido inicialmente en 1 -> StartPos = 1), la cadena sobre la que se trabajo, pasada como parámetro a la función (Source) y la palabra a buscar, también pasada como parámetro (Search). Como ya sabemos, InStr()) nos devolverá, en CurrentPos, la posición en la que inicia su presencia la palabra que buscamos (Search(4).

Este proceso se mantendrá activo (gracias al bucle) mientras que cumpla la condición (CurrentPos <> 0), lo cual dejará de suceder cuando, gracias a la función  InStr(), la subcadena buscada ya no se encuentre en el segmento de la cadena originaria sobre la que trabajamos, dado que InStr() devuelve 0 cuando se da esta condición (5).

También en función de la condición que rige el bucle (Do While CurrentPos <> 0 -> If CurrentPos <> 0 Then), el condicional anidado desarrolla una serie de operaciones que implican el uso de las funciones Mid() [ver aquí] y Len() [ver aquí].

La primera operación (Result = Result + Mid(Source, StartPos, (CurrentPos - StartPos))) permite asignar a la variable Result el contenido previo de la misma más el resultado de la función Mid() (6), esto es: una subcadena.

La segunda operación (Result = Result + NewPart) concatena Result con la subcadena que obtuvimos con la primera sobre la propia variable Result.

Y la tercera (StartPos = CurrentPos + Len(Search)) modifica el valor de la variable StartPos (recordemos, la que marca la posición de inicio de la búsqueda), sumando al valor actual de la variable CurrentPos el tamaño de la subcadena que buscamos, obtenido mediante la función Len() (Len(Search)).

Cuando la condición inicial (If CurrentPos <> 0 ) deja de cumplirse entra en juego la segunda parte del condicional (Else), que desarrolla la operación final sobre la variable Result (Result = Result + Mid(Source, StartPos, Len(Source))), que consiste en devolver como resultado la concatenación de la subcadena Result con lo que devuelve de nuevo la función Mid() trabajando los parámetros cadena original (Source), el valor que corresponde a la variable StartPos (que ha sido modificada previamente por la instrucción StartPos = CurrentPos + Len(Search)) y la longitud de la cadena inicial obtenida mediante la función Len() (Len(Source)).

Al finalizar este condicional, una vez que deja de cumplir la condición de partida (CurrentPos <> 0), se cierra el condicional y el propio bucle y ya sólo resta devolver la nueva cadena (esto es, la original modificada mediante la sustitución de la palabra seleccionada para la búsqueda por la palabra que la sustituye) como resultado de la función (Replace = Result).

Si lo llevamos a la práctica, dado el script...

Sub Cad6ByR

Dim sCad1Ini As String, sCad2Fin As String
Dim sResultaBusca As Integer
 
sCad1Ini = "Aquí hay una cadena"

sCad2Fin = Replace (sCad1Ini,"hay", "está")

MsgBox sCad1Ini & Chr(13) & sCad2Fin

End Sub

... la llamada a la función Replace() (sCad2Fin = Replace (sCad1Ini,"hay", "está")) nos permite obtener como resultado la cadena Aquí está una cadena, referenciada en la variable sCad2Fin; siendo que hemos solicitado que la subcadena (la palabra) "hay" (segundo parámetro) sea sustituida por la subcadena "está" (tercer parámetro) en la cadena originaria "Aquí hay una cadena" (primer parámetro), referenciada por la variable sCad1Ini.

Esta nada sencilla función Replace() (7) no es la única opción para reemplazar palabras. Los colaboradores de [wiki.open-office.es] han desarrollado una alternativa, la función ReplaceAll(), que es también muy interesante. Dado lo extenso de esta entrada he considerado postponer para una [nueva entrada] el estudio de esta segunda función.

NOTAS

(1) En LO-Writer [Editar | Buscar] y [Editar | Buscar y Reemplazar] respectivamente. No veo necesario explicar ni el funcionamiento de estas funcionalidades ni su interés para el usuario, ya que forman parte de sus conocimientos básicos. Otra cosa es que su uso no sea ni todo lo frecuente que podría ser ni se obtenga de ellas la utilidad que se podría obtener. Pero estas son otras cuestiones.
(2) En el ejemplo se definen como Long, pero pueden definirse en la mayoría de los casos como Integer, ya que no son necesarios números tan grandes para que Replace() cumpla su objetivo.
(3) Este uso de funciones dentro de funciones, sean las primeras de tipo Built-In o creadas, es usado muy frecuentemente, ya que incrementa la potencia de procesamiento de las funciones.
(4) Para más información sobre InStr(), consultar [esta entrada]
(5) Esto explica que utilicemos el parámetro de inicio de búsqueda en la función InStr(). (InStr(StartPos, Source, Search)) y que asignemos el resultado que devuelve a la variable que condiciona el funcionamiento del bucle. Dicho de otra forma, InStr() es, en realidad, el controlador que nos permite salir de un bucle que, en caso contrario, sería infinito, ya que CurrentPos tiene, de partida, un valor diferente de 0 (CurrentPos = 1) y sólo vale 0 cuando InStr() devuelve ese valor. 
(6) que trabaja con estos tres parámetros: la cadena sobre la que trabajamos (Source), la posición de inicio (StartPos) y la diferencia entre el valor de la variable CurrentPos menos el de la posición de inicio (CurrentPos - StartPos)
(7) Desde el punto de vista didáctico, esta función es de gran utilidad, ya que permite comprobar el resultado que podemos obtener combinando estructuras y utilizando diferentes funciones Built-In.

sábado, 28 de septiembre de 2024

Funciones. Textos.

Componer y descomponer una cadena.

Aunque, como hemos visto, una cadena puede ser simple (esto es, estar formada por una única palabra, por ejemplo), son las cadenas complejas las que nos interesan en nuestro trabajo, ya que son con las que trabajamos. Entiendo por cadena compleja aquella que está formada por varias palabras, pudiendo diferenciar al menos dos subtipos: las cadenas elementales, que están formadas por una frase simple, y las extensas, dentro de las que podemos identificar como párrafo o como texto. Aunque todas las cadenas complejas nos interesan, más aun las extensas. De ahí el interés que tiene conocer funciones que nos permitan trabajar con ellas.


Las dos funciones que trataré en esta entrada son ambas de tipo Built-In y se pueden considerar funciones a medio camino entre el tratamiento de textos y el trabajo con colecciones de datos (en este caso, listas), pero he preferido incluirlas en este subapartado de funciones de texto por el objeto con el que ambas trabajan: los string.

También conviene decir desde el principio, que sirven para trabajar con cadenas de texto complejas (según quedaron definidas éstas al inicio de la entrada), pero no de forma específica con textos extensos: es suficiente con que el string contenga varias palabras para que ambas sea de utilidad. Por motivos didácticos, en esta entrada no desarrollaremos ejemplos de uso con textos extensos, ya que el objetivo actual es aprender la sintaxis y el uso de las funciones (1). 

Dicho lo anterior, y entrando en materia, las funciones Join() (unir) y Split() (dividir) son dos funciones contrarias y por ello mismo complementarias: como sus nombres indican, la primera no permite unir en una única cadena el conjunto de elementos (palabras) que conforman una lista y la segunda separar o dividir los elementos (las palabras) que forma una cadena, convirtiéndolos en elementos de una lista.

La función Join() recibe dos argumentos: la lista de elementos (matriz) y el carácter que servirá de separador (variable). Esta es su expresión completa como función: Join( mListaPal(), sSepara) (2) y este un ejemplo de uso...

 Sub JuntarPalabras
 Dim mListaPal() As String
 Dim sSepara As String, sFrase As String
 
 mListaPal () = Array("El","pelo","de","Rosa","es","muy","bonito")
 sSepara = "-"
 sFrase = Join( mListaPal(), sSepara)
 
 MsgBox sFrase
 
 End Sub 

... cuyo resultado expresado (output) mediante MsgBox será el siguiente El-pelo-de-Rosa-es-muy-bonito.

Dado que este resultado no se ajusta a lo que esperamos como frase, será suficiente con sustituir el carácter asignado a sSepara por sSepara = " " (espacio) para apreciar mejor la utilidad de la función: El pelo de Rosa es muy bonito (3).

La función Split() es, como dije, la contraria de Join(): en este caso tratamos con una cadena (compleja) y obtenemos una lista de palabras. Para ello Split() recibe también dos parámetros de tipo String: la cadena de texto (o la variable a la que éste esté referenciado) y el grafema que servirá de referencia para la diferenciación de los elementos. Su sintaxis más simple es la siguiente: Split(sCadena, sSepara) (4) y esta una posible expresión concreta: Split("El pelo de Rosa es muy bonito"," "). Veamos una concreción...

Sub SepararPalabras
Dim sFrase As String, sSepara As String
Dim mListaPal() As String
Dim i As Integer 

sFrase = "El pelo de Rosa es muy bonito"
sSepara = " "
mListaPal = Split ( sFrase(), sSepara)
For i = LBound(mListaPal()) To UBound(mListaPal()) (5)
    MsgBox mListaPal(i)
Next 
End Sub 

... que nos devuelve, palabra a palabra, cada una de las que conforman sFrase.

En [esta entrada] veremos un uso especialmente interesante de ambas funciones.

NOTAS

(1) No es OOo Basic un lenguaje pensado para desarrollar procesos complejos de análisis de textos, así que tampoco debemos pensar el crear proyectos de gran envergadura en lo relativo al trabajo con textos complejos y extensos como los que son habituales en nuestro trabajo, pero el uso de estas funciones (en combinación con otras de esta misma temática), junto con el tratamiento de listas y matrices nos abre la posibilidad de crear procedimientos de trabajo más complejos de los que podríamos desarrollar sin su ayuda y, llevados estos procedimientos a la práctica, abordar el tratamiento de ítem de respuesta abierta, por poner un ejemplo. Algo que hasta ahora resultaba muy difícil de plantear.
(2) Así como es más que conveniente que el primer argumento haya sido definido previamente como lista (matriz), el segundo puede incorporarse directamente como string en lugar de hacerlo mediante una variable. Por ello, puede ser incluso más frecuente encontrar expresiones de la función que se ajusten a este modelo (Join( mListaPal(), "-") que la que he expuesto como modelo.
(3) Así como el objetivo de la matriz mListaPal era mostrar la relación entre este tipo de matrices y el trabajo con cadenas, el grafema "-" pretendía evidenciar la multiplicidad de formas de uso de la función Join(), que obviamente no se limita a la de facilitar la composición de frases, aunque ésta sea su mayor utilidad para nosotros, al menos en este momento y en función de la complementariedad de Join() con Split(). Sirva esta nota para advertir de posibles confusiones que yo mismo puedo provocar en mi exposición.
(4) En este caso ambos pueden expresarse directamente sin necesidad de usar variables, pero parece conveniente y más flexible asociar variables como parámetros, al menos en lo que se refiere al primer parámetro.
(5) Este bucle no tiene más objetivo que permitir observar que mListaPal() contiene los elementos esperados en función de la aplicación de la función Split(). Obsérvese que el objetivo del ejemplo es incidir en la complementariedad de esta función con la anterior; de ahí también la denominación de la matriz y de las variables.

jueves, 26 de septiembre de 2024

Funciones. Textos.

Repetir una cadena n-veces.

Presento a continuación una función creada (no Built-In) que permite repetir n-veces un string (carácter, palabra o frase). El código original de esta función lo puedes encontrar en [wiki.open-office.es] con el nombre de StrRepeat().


Para facilitar la plena comprensión de StrRepeat() empiezo por renombrarla como RepiteCad() y sigo con su explicación.

La función RepiteCad() recibe dos parámetros, el primero de tipo String (el contenido textual que deseamos se repita) y el segundo numérico (el número de repeticiones deseadas), de modo que el enunciado de la función podría quedar como sigue: RepiteCad(sCad, iVeces).

Explico a continuación el contenido y su funcionamiento:

Function RepiteCad( sCad As String, iVeces As Integer) As String

Dim sRes As String

Dim i As Integer

For i= 1 To iVeces

sRes = sRes & sCad

Next

RepiteCad = sRes

End Function

En esta función se declaran dos variables, una de ellas (sRes) para  contener la cadena resultante de la repetición y otra (i) como contador.

Incluye un bucle For que ejecuta el ciclo de repeticiones requerido iniciando el contador a 1 y finalizándolo con el valor pasado como segundo parámetro (el número de repeticiones deseado) (For i= 1 To iVeces).

Lo que ejecuta ese bucle es precisamente es la concatenación repetida iVeces de su variable de respuesta a la cadena pasada como primer parámetro (el contenido textual que deseamos se repita) (sRes = sRes & sCad)

Un ejemplo de funcionamiento podría ser el siguiente:

Sub LLamarFuncRepetir

Dim Cadena As String

Cadena = RepiteCad ("P ", 7)

MsgBox Cadena

End Sub


Function RepiteCad( sCad As String, iVeces As Integer) As String

Dim sRes As String

Dim i As Integer

For i= 1 To iVeces

sRes = sRes & sCad

Next

RepiteCad = sRes

End Function

Funciones. Textos.

Subcadenas.

Especial interés tiene el acceso a subcadenas o partes de una cadena para su procesamiento. Para ello OOo Basic provee de cuatro funciones Built-In, tres para el acceso propiamente dicho a subcadenas y una cuarta para la ubicación de la subcadena en la cadena. Analizaré estas funciones en esta entrada.


Como acabo de decir, para acceder a parte del string o cadena contamos con tres funciones: Left()Right() y Mid() que, como sus nombres indican, nos permiten posicionarnos al inicio (extremo izquierdo), al final (extremo derecho) o en una posición intermedia de la cadena respectivamente (1).

Las dos primeras funciones (Left() y Right()) reciben dos parámetros: la cadena de referencia (String) y número de caracteres a devolver, Left() desde la posición inicial y Right() desde la final. 

La función (Mid()), como es de esperar, requiere tres parámetros: la cadena en la que buscar (String), la posición de partida de la búsqueda y el número de caracteres a devolver (ambos Integer). Veámos su sintaxis y funcionamiento en la práctica dada la variable sCad1 = "Califragilistico":
  • vSubCad1 = Left (Cad1, 4) devuelve Cali
  • vSubCad1 = Right (Cad1, 4) devuelve tico
  • vSubCad1 = Mid (Cad1, 3, 4) devuelve lifr (2)
La función complementaria de las anteriores es la función InStr() (3). Esta función requiere dos parámetros, ambos de tipo string, y devuelve un valor numérico (Integer). El primero de los parámetros es la cadena (o variable) sobre la que queremos trabajar y el segundo, la subcadena que buscamos (que también podemos asignar a una variable, por ejemplo sParte). El valor numérico que nos devuelve, en caso de que efectivamente la subcadena forme parte de la cadena, es la posición que ocupa el primer elemento de la subcadena buscada en la cadena de referencia. En caso de no encontrar dicha subcadena, InStr() devuelve (4).

Igual que antes, un ejemplo de sintaxis y resultado: sobre la variable anterior (sCad1 = "Califragilistico") queremos saber si contiene la subcadena fragil (sParte = "fragil"), con lo que formulamos la función como sigue, siendo sResultaBusca una variable de tipo Integer a la que asignamos el resultado de la función:

sResultaBusca = InStr (sCad1, sParte)

Si formulamos MsgBox sResultaBusca obtendremos como resultado 5, que es la posición en la que se inicia la presencia de la subcadena sParte. En caso de que la subcadena que buscamos no se encuentre en la cadena-base, como ya dije, InStr() nos devolverá 0

Una limitación relevante de InStr() es que únicamente devuelve la primera aparición de la subcadena buscada, no todas las posibles. Así, por ejemplo, si la subcadena a buscar fuera li (que está presente dos veces en "Califragilistico"), la respuesta será 3, que es la posición inicial (de la letra l) de la primera aparición de la subcadena, pero no dice nada de la segunda aparición de dicha subcadena (5).

Existe una forma de sortear esta dificultad, aunque no resulta del todo satisfactoria, ya que exige para su aprovechamiento, elaborar una función propia, pero al menos posibilita esta solución: consiste en añadir un nuevo parámetro a la función, posicionado al inicio de su declaración: este parámetro (que es de tipo numérico) indica la posición a partir de la cual iniciar la búsqueda. Su sintaxis es la siguiente: sResultaBusca = InStr (iPos, sCad1, sParte), siendo iPos una variable que contiene un valor numérico (6).

Siguiendo con el ejemplo anterior, si formulamos sResultaBusca = InStr ( iPos, sCad1, sParte), para iPos = 4, obtendremos como resultado 10, que es la posición en la que se ubica la letra l en la aparición de la subcadena li dentro de la cadena "Califragilistico".


NOTAS

(1) Y de ahí sus nombres en inglés, evidentemente: Left(), Right() y Mid().
(2)IMPORTANTE: obsérvese que el punto de partida es la posición 3, esto es: la tercera letra empezando por la izquierda (la l) y no la cuarta (la i) como sería de esperar según la forma ordinaria en la que OOo Basic posiciona los elementos de su conjuntos de datos, identificando el primer elemento con la posición 0. La función Mid() es, en esto, una excepción, aunque no la única. Además, este punto de inicio está incluido en la subcadena que devuelve Mid(), esto es, no empieza a contar a partir de él, de ahí que la subcadena devuelta sea lifr.
(3) Se puede traducir por EnLaCadena, en evidente referencia a su función.
(4) Como veremos más adelante en la entrada, InStr() también puede recibir un tercer parámetro. En este caso también se cumple el criterio indicado en (el conteo empieza en 1, no en posición 0), por lo que el valor que devuelve InStr() lo que nos indica es que la subcadena NO forma parte de la cadena. Téngase en cuenta que es suficiente con que un elemento de la subcadena buscada sea diferente (uno sólo, y  no necesariamente el primero) para que la respuesta sea 0.
(5) Esto hace que InStr() resulte de utilidad limitada en búsquedas de cierta complejidad.