Saltar al contenido principal

Funciones sobre cadenas de texto

Introducción​

Las cadenas de texto (texto, string) pueden aparecer como parte de un protocolo de dispositivo, p. ej., como mensaje de error de un subsistema o de la transmisión de datos de medición a través de una interfaz serie. Muchos protocolos de comunicación basados en web también se construyen sobre cadenas de texto.

El módulo Math admite el tipo escalar string, que normalmente contiene caracteres codificados en UTF-8.

Todos los tipos de datos pueden convertirse al tipo string, p. ej., con str(), o a los tipos de destino correspondientes con los demás operadores de conversión (cast), siempre que no se produzcan errores de sintaxis.

Operadores sobre texto​

Con el tipo de datos string se admiten los siguientes operadores:

  • todos los operadores de comparación, aplicándose el orden numérico de los caracteres ASCII: p. ej., '4' < 'A' < 'a'

  • operador +, concatena dos cadenas

    s_connected = s1 + s2;
    consejo

    str(x) convierte cualquier tipo de datos en una representación de cadena, también objetos multidimensionales como vectores y matrices. Para tener más control sobre el formato puede resultar útil la función sFormat(f, ...).

Propiedades y funciones básicas​

Longitud de una cadena de texto "sLength"​

La longitud de una cadena s en bytes se calcula de la siguiente manera

l = sLength(s);

En la codificación UTF-8, con la codificación correspondiente, los caracteres especiales también pueden ocupar varios bytes. Esta función determina el número de bytes, no el número de caracteres (imprimibles).

Extracción de una subcadena como copia "sCopy"​

Una subcadena r de la cadena s puede extraerse de la siguiente manera

r = sCopy(s, b); // Kopie der Zeichenkette s ab Position b
r = sCopy(s, b, c); // Kopie der Zeichenkette s ab Position b der Länge c
r = sCopy(s, BC); // BC ist ein Vektor der Länge 2, der b und c beinhaltet (Verhalten wie bei sCopy(s, b, c)
r = sCopy(s, BC, sel); // BC ist eine Matrix mit zwei Spalten, die zu b und c korrespondieren,
// wobei sel einen selektierenden Zeilenindex darstellt

La matriz BC es en muchos casos el resultado de funciones de búsqueda, p. ej., sFind(), que pueden devolver varias coincidencias en la cadena. Mediante el índice sel puede extraerse directamente la parte de texto correspondiente.

Ejemplo:​

// 0 1 2 3
// 0123456789012345678901234567890123456789
geo = 'lat: 51.234567, lon: 12.3456789';
p6 = sFind(geo, 'lat:\s*([0-9.+-]+)', {subex: true});
// => p6 := [ [ 0,14] // refers to 'lat: 51.234567'
// , [ 5, 9]]; // refers to '51.234567'
lat = dbl(sCopy(geo, p6, 1));
// => lat := 51.234567;

Extracción del inicio y del final de la cadena "sLeft", "sRight"​

El inicio b y el final e de longitud l de la cadena s pueden obtenerse como copia de la siguiente manera

b = sLeft(s,l);
e = sRight(s,l);

Eliminación de una subcadena "sErase"​

Para obtener una copia de una cadena s de la que se ha eliminado una subcadena, puede utilizarse lo siguiente

r = sErase(s, b); // Kopie der Zeichenkette s ohne Zeichen ab Position b
r = sErase(s, b, c); // Kopie der Zeichenkette s ohne Zeichen ab Position b der Länge c
r = sErase(s, BC); // BC ist ein Vektor der Länge 2, der b und c beinhaltet (Verhalten wie bei sErase(s, b, c)
r = sErase(s, BC, sel); // BC ist eine Matrix mit zwei Spalten, die zu b und c korrespondieren,
// wobei sel einen selektierenden Zeilenindex darstellt

La matriz BC es en muchos casos el resultado de funciones de búsqueda, p. ej., sFind(), que pueden devolver varias coincidencias en la cadena. Mediante el índice sel puede eliminarse directamente la parte de texto correspondiente.

Inserción de una cadena "sInsert"​

Para insertar una cadena t dentro de una cadena s en la posición b y devolver una copia r, puede utilizarse lo siguiente

r = sInsert(s, b, t);

Crear, formatear, leer, limpiar​

Extracción de valores de una cadena "sScan" 1​

Esta función extrae valores de una cadena s a partir de una cadena de formato f:

v = sScan(f, s);

La cadena de formato f contiene marcadores de posición de la forma %<x> (la letra tras % es arbitraria y no influye en el tipo del resultado), así como partes literales que sirven de separadores en la cadena de origen. Para cada marcador de posición se extrae la parte de texto situada entre los literales y se convierte automáticamente al tipo de datos adecuado.

// Einzelner Wert → Skalar
lat = sScan('lat: %v', zeile); // => 51.234 (dbl)
port = sScan('port=%d', konfig); // => 8080 (uint)

// Mehrere Werte gleichen Typs → Vektor
v = sScan('lat: %v, lon: %v', zeile); // => [51.234, 12.345] (dbl-Vektor)

// Gemischte Typen → zeilenweise als String, adressierbar mit sLine()
raw = sScan('name: %v, age: %v', s); // => "Alice\n30"
name = sLine(raw, 0); // => "Alice"
age = sLine(raw, 1); // => "30"
ComportamientoDescripción
Último marcador de posición sin literal de cierrelee hasta el final de la cadena
Comillas alrededor de un valorse eliminan automáticamente
Literal de la cadena de formato no encontradodevuelve cErr
Ningún marcador de posición en la cadena de formatodevuelve cErr

Formato de una cadena "sFormat"​

Para representar con formato, como cadena r, una cadena f que contiene, p. ej., valores numéricos, puede utilizarse la siguiente función

r = sFormat(f, ...);

Aquí, f representa una cadena de formato del tipo de printf(), y para cada marcador de posición de la forma %[<width>][.<precision>]<type> debe indicarse un argumento correspondiente.

  • <width>: ancho de campo opcional para la salida, width < 0: alineado a la izquierda

  • .<precision>: opcional para f/g/e, número de decimales o de cifras significativas

  • <type>: los argumentos se convierten según el tipo de salida elegido. Por ello no se necesitan indicaciones de longitud adicionales para el tipo de datos.

    <type>Tipo de datosSalida
    b<bool>Salida de 'false' o 'true'
    d<int>Número entero con signo, base 10
    u<uint>Número entero sin signo, base 10
    x, X<uint>Número entero sin signo, base 16
    cifras A-F en minúscula (x) o mayúscula (X)
    o<uint>Número entero sin signo, base 8
    f<dbl>Número de coma flotante sin exponente de 10
    Ejemplo: 1234.5678
    g<dbl>Número de coma flotante en representación optimizada
    como f o e según el orden de magnitud del número.
    Ejemplos: 1234.45678, 1.2345e9, 1.2345e-12
    e<dbl>Número de coma flotante con exponente de 10
    Ejemplo: 1.2345678e3
    s<str>Texto
    c2<uint>Carácter Unicode con este código, codificado en UTF-8
    Ejemplo: 0xE4 → ä; código no válido → U+FFFD (�)

Ejemplo:​

template = 'alt: %6.2f, lat: %.9f, lon: %.9f';
tx = sFormat(template, 140.4, 49.8765432, -3.14);
// tx := 'alt: 140.40, lat: 49.876543200, lon: -3.140000000';

Cadena a partir de códigos de carácter "mkString" 2​

Un vector A de números enteros (int o uint) se lee como una secuencia de códigos de carácter y se convierte en una cadena s

s = mkString(A);
s = mkString(A, {encoding: 'windows-1252', keepNull: false, masking: auto});

Cada elemento de A es una unidad de código de la codificación encoding: un byte en UTF-8 y en las codificaciones de 8 bits, 16 bits en UTF-16 y un carácter (code point) en UTF-32. El resultado, como toda cadena, está codificado en UTF-8.

OpciónValor por defectoSignificado
encoding'UTF-8'Nombre de la codificación, p. ej., 'UTF-8', 'ISO-8859-1', 'windows-1252', 'UTF-16', 'UTF-16BE', 'UTF-32'. Una codificación desconocida para el sistema provoca un error.
keepNullfalsefalse: la cadena termina en el primer carácter nulo. true: los caracteres nulos se conservan en la cadena.
maskingautoauto: cada elemento se enmascara al ancho de una unidad de código (8, 16 o 21 bits); los bits de mayor peso se ignoran.
off o 0: sin enmascaramiento; un elemento fuera del rango de valores provoca un error.
nn (de 1 a 32): máscara de nn bits; n≤8n \leq 8 lee bytes también en UTF-16 y UTF-32, cuyo orden queda determinado por el nombre de la codificación (p. ej., 'UTF-16BE').
Codificaciones disponibles

'UTF-8', 'ISO-8859-1', 'windows-1252' y 'UTF-32' están siempre disponibles. Todas las demás codificaciones, incluida 'UTF-16', dependen de los componentes del sistema instalados en el dispositivo.

Si UTF-16 o UTF-32 se leen byte a byte (masking ≤8\leq 8), el nombre debería indicar el orden de los bytes, p. ej., 'UTF-16BE' o 'UTF-32LE'. Sin esta indicación y sin marca de orden de bytes (byte order mark), se aplica el orden de bytes del dispositivo.

Una secuencia de caracteres no válida se sustituye por el carácter de sustitución U+FFFD (�). Si A no es un vector de int o uint, el resultado es un error.

Ejemplo:​

// versión de software, transmitida como caracteres individuales en cuatro canales
A_Str = [swVer_C1, swVer_C2, swVer_C3, swVer_C4];
s = mkString(A_Str); // p. ej. '1.04'

t = mkString([0x80, 0xE4], {encoding: 'windows-1252'}); // 'ۊ'
u = mkString([0x00, 0x41, 0x20, 0xAC], {encoding: 'UTF-16BE', masking: 8}); // 'A€'

Acceso al contenido de un recurso "sResource"​

La función devuelve el contenido del recurso indicado como cadena constante (binaria).

resStr = sResource({@ref:'myResource'});
aviso

Según la configuración, el contenido del recurso puede contener no solo texto UTF-8 puro (p. ej., un archivo INI o un objeto JSON), sino también datos binarios, como arrays de tipo double, imágenes jpg, etc. En particular, los datos binarios solo deben ser procesados por funciones especiales adecuadas. Para la implementación de tales funciones, no dude en ponerse en contacto con nosotros.

Eliminación de espacios en blanco "sTrim"​

Esta función elimina todos los espacios en blanco (whitespace) al principio y al final del argumento, como por ejemplo en

s_trimmed = sTrim(s);

Conversión a mayúsculas/minúsculas "sUpper", "sLower"​

La conversión de una cadena en cuanto a mayúsculas y minúsculas se realiza mediante

s_uppercase = sUpper(s);
s_lowercase = sLower(s);

Simplificación "sSimplify" de cadenas​

La función sSimplify() sustituye todas las apariciones múltiples de espacios en blanco (espacios, tabuladores, CR, LF, ...) por un único espacio.

s_simple = sSimplify(s);

Normalización "sNormalize" de cadenas​

La función sNormalize() elimina las comillas correspondientes "..." o '...' al principio y al final de la cadena y sustituye todas las secuencias de ESCAPE \ por el código que designan.

s_normalized = sNormalize(s);

Buscar, encontrar y descomponer​

Búsqueda de subcadenas "sFind"​

La función de búsqueda sFind devuelve el índice r o una matriz con la posición y la longitud de las partes de texto encontradas del patrón p en la cadena s, y puede utilizarse de la siguiente manera

r1 = sFind(s, {...}); // Konfiguration des 'pattern' ist zwingend
r1 = sFind(s,p); // direkte Suche ab Stringbeginn
r2 = sFind(s,p,b); // direkte Suche ab Position b
// Optionales Konfigurationsobjekt für alle Varianten
rx = sFind(..., { pattern: <string>
, case: <bool>
, all: <bool>
, regex: <bool>
, subex: <bool>
});

Si no se encuentra ningún patrón, esta función devuelve -1.

Una matriz con los resultados de la búsqueda tiene la siguiente estructura:

rx=[s0c0s1c1⋮⋮sn−1cn−1]rx = \left[ {\begin{array}{cc} {{s_0}}&{{c_0}}\\ {{s_1}}&{{c_1}}\\ \vdots & \vdots \\ {{s_{n - 1}}}&{{c_{n - 1}}} \end{array}} \right]

Esta matriz puede pasarse directamente, junto con el número de fila del resultado individual, a las funciones sCopy() o sErase().

Un resultado individual puede procesarse con la función GetRow() o mediante la indicación directa de la indexación:

part4 = sCopy(s, rx, 3); // counting from zero
part4a = sCopy(s, rx[3,0], rx[3,1]); // equivalent
part4_sc = GetRow(rx, 3); // vector [s3, c3]
part4b = sCopy(s, part4_sc); // equivalent
PropiedadValorDescripción
pattern<str>Patrón de búsqueda constante, si no se utiliza el parámetro p.
Es algo más eficiente en los modos regex, ya que la expresión no tiene que compilarse de nuevo cada vez.
case<bool>Búsqueda distinguiendo mayúsculas y minúsculas (def.: false, sin distinguir mayúsculas y minúsculas)
all<bool>Devuelve un vector con las posiciones iniciales y las longitudes de las partes de texto coincidentes,
no en combinación con subex
regex<bool>Interpreta el patrón pattern o p como expresión regular; el resultado es una matriz con la posición y la longitud de las expresiones/subexpresiones encontradas
subex<bool>Devuelve la posición y la longitud de las partes de texto extraídas en una matriz de resultados,
activa regex automáticamente

Ejemplos​

// 0 1 2 3
// 0123456789012345678901234567890123456789
str = 'Hello world and hello my dear friends!';

p0 = sFind(str, "dog");
// => p0 := -1; // not found, independant of selected modes
// my test with (p0 < 0) ? ... : ...
// or isMatrix(p0) ? ... : ... for 'all'- or 'regex'-modes

p1 = sFind(str, "hello");
// => p1 := 0;

p2 = sFind(str, "hello", {case: true});
// => p2 := 16; // first one is now skipped

p3 = sFind(str, "hello", {all: true});
// => p3 := [ [ 0, 5]
// , [16, 5]];

p4 = sFind(str, "(and|dear)", { regex: true, all: true});
// => p4 := [ [12, 3]
// , [25, 4]];

p5 = sFind(str, 'dear\s+(\w+)', { subex: true });
// => p5 := [ [25, 12] // first row is complete match
// , [30, 7]]; // then (...) extractions follow

dear= sCopy(str, p5, 1);
// => dear:= 'friends';

// 0 1 2 3
// 0123456789012345678901234567890123456789
geo = 'lat: 51.234567, lon: 12.3456789';
p6 = sFind(geo, 'lat:\s*([0-9.+-]+)', {subex: true});
// => p6 := [ [ 0,14]
// , [ 5, 9]];
lat = dbl(sCopy(geo, p6, 1));
// => lat := 51.234567;

Sustitución de subcadenas "sReplace"​

Para sustituir (varias) cadenas t_k dentro de la cadena s por el texto correspondiente de cada s_k, puede utilizarse lo siguiente

r = sReplace(s,t_1,s_1, ..., t_N,s_N);

La sustitución se realiza de forma secuencial en el orden de los argumentos; los valores s_k se convierten implícitamente a una representación de texto. Para tener más control sobre la conversión puede utilizarse la función sFormat().

Ejemplo:​

template = 'alt: <alt>, lat: <lat>, lon: <lon>';
tx = sReplace(template, '<alt>', 140.4, '<lat>', 49.8765432, '<lon>', -3.14);
// tx := 'alt: 140.400000, lat: 49.876543, lon: -3.140000';

Búsqueda de una combinación clave-valor "sGetKV" 1​

Esta función busca la clave k en una cadena (bloque de texto) s y devuelve el valor correspondiente. La búsqueda no distingue entre mayúsculas y minúsculas.

v1 = sGetKV(s, k);
// Optionaler Konfigurationsblock
vx = sGetKV(..., { format: <enum>
, filter: <regex>
, index: <uint>
});
PropiedadValorDescripción
format<enum>Establece el formato del bloque de texto y define el filter estándar adecuado. Valores posibles: json (estándar), ini, xml_attr, xml_node
filter<regex>Sobrescribe el estándar del formato: expresión regular que captura, tras el nombre de la clave, el valor correspondiente como grupo de captura (...)
index<uint>Selecciona la N-ésima coincidencia (base 0, estándar: 0). Útil cuando una clave aparece varias veces, p. ej., en elementos XML repetidos.

Si no se encuentra la clave (o el índice supera el número de coincidencias), la función devuelve cErr. Las comillas alrededor del valor encontrado se eliminan automáticamente.

Variantes de formato​

FormatoSeparadorEjemplo típico
json (estándar): tras la comilla de cierre opcional{"key": "value", "count": 3}
ini=, valor hasta el final de la líneahost=localhost\nport=8080
xml_attr=, valor entre comillas<device id="42" name="sensor"/>
xml_nodeetiqueta XML <key>…</key><voltage>3.3</voltage>

Elementos anidados y repetidos​

sGetKV no evalúa la profundidad de anidamiento. En objetos anidados (p. ej., {"outer": {"inner": 1}}), index:0 apunta a la clave exterior; una búsqueda dirigida a valores de niveles inferiores requiere una evaluación en dos pasos: primero extraer el valor de la clave exterior y, a continuación, aplicar de nuevo sGetKV sobre él.

Los elementos repetidos de la misma clave (p. ej., <val>10</val><val>20</val>) pueden seleccionarse con index.

Ejemplos​

cfg = '{"name": "Alice", "count": 3}';
name = sGetKV(cfg, 'name'); // => "Alice"
cnt = sGetKV(cfg, 'count'); // => 3 (uint)

ini = 'host=localhost\nport=8080';
port = sGetKV(ini, 'port', {format:'ini'}); // => 8080 (uint)

xml = '<data><voltage>3.3</voltage></data>';
u = sGetKV(xml, 'voltage', {format:'xml_node'}); // => 3.3 (dbl)

// Zweites Vorkommen eines wiederholten XML-Elements
seq = '<data><val>10</val><val>20</val><val>30</val></data>';
v1 = sGetKV(seq, 'val', {format:'xml_node'}); // => 10
v2 = sGetKV(seq, 'val', {format:'xml_node', index:1}); // => 20

// Eigener Filter für abweichende Syntax (key => value; ...)
v = sGetKV(s, 'temp', {filter:'\s*=>\s*([^;]+)'});

División de cadenas "sSplit"​

Para dividir una cadena en un carácter ch puede utilizarse la función sSplit. Esta devuelve una matriz de dos columnas con todas las posiciones iniciales y longitudes de las subcadenas correspondientes

r1 = sSplit(s, ch);
// Optionaler Konfigurationsblock
rx = sSplit(..., { trim: <bool>
});
pos = rx[0, 0];
len = rx[0, 1];
PropiedadValorDescripción
trim<bool>Elimina los espacios en blanco al principio y al final de los elementos

Número de líneas dentro de una cadena "sLines"​

El número de líneas de una cadena s puede determinarse de la siguiente manera

lines = sLines(s);

Se admiten todas las variantes de saltos de línea (LF, CRLF, LFCR, CR).

Extracción de una línea de una cadena multilínea "sLine"​

Para extraer la i-ésima línea de una cadena s resulta adecuada la siguiente función

lineI = sLine(s,i);
// Optionales Konfigurationsobjekt
lineX = sLine(..., { trim: <bool>
});
PropiedadValorDescripción
trim<bool>Elimina los espacios en blanco al principio y al final de la línea

Lectura de líneas completas "sGetline"​

La función sGetline() une los distintos valores del canal de tipo cadena s y los almacena hasta que puede emitirse una línea completa. Esta se retira del búfer y, con el resto que queda, se continúa la acumulación.

Para obtener una línea completa a partir de un flujo de caracteres puede utilizarse lo siguiente

line1 = sGetline(s);
// Optionales Konfigurationsobjekt
lineX = sGetline(..., { trim: <bool>
, eoln: <str>
, timeout: off|<time>
});
PropiedadValorDescripción
trim<bool>La línea emitida se limpia además de espacios
eoln<string>Definición del final de línea
timeoutoff/<time>Tiempo en segundos tras el último fragmento hasta que se inserta un final de línea.
off2 o 0: sin final de línea tras el vencimiento del tiempo (def.)

Footnotes​

  1. Disponible a partir de la versión 13 del catálogo. ↩ ↩2

  2. Disponible a partir de la versión 14 del catálogo. ↩ ↩2 ↩3