Passa al contenuto principale

Funzioni sulle stringhe

Introduzione​

Le stringhe (testo, string) possono comparire come parte di un protocollo di dispositivo, ad es. come messaggio di errore di un sottosistema o nella trasmissione di dati di misura tramite un'interfaccia seriale. Anche molti protocolli di comunicazione basati sul web si fondano su stringhe.

Il modulo Math supporta il tipo scalare string, che tipicamente contiene caratteri codificati in UTF-8.

Tutti i tipi di dati possono essere convertiti nel tipo string, ad es. con str(), oppure nei rispettivi tipi di destinazione con gli altri operatori di cast, purché non si verifichino errori di sintassi.

Operatori sul testo​

Con il tipo di dati string sono supportati i seguenti operatori:

  • tutti gli operatori di confronto, dove vale l'ordine numerico dei caratteri ASCII: ad es. '4' < 'A' < 'a'

  • operatore +, concatena due stringhe

    s_connected = s1 + s2;
    suggerimento

    str(x) converte qualsiasi tipo di dati in una rappresentazione di stringa, anche oggetti multidimensionali come vettori e matrici. Per avere più controllo sulla formattazione può essere utile la funzione sFormat(f, ...).

Proprietà e funzioni di base​

Lunghezza di una stringa "sLength"​

La lunghezza di una stringa s in byte si calcola come segue

l = sLength(s);

Nella codifica UTF-8, con la relativa codifica, i caratteri speciali possono occupare anche più byte. Questa funzione determina il numero di byte, non il numero di caratteri (stampabili)!

Estrazione di una sottostringa come copia "sCopy"​

Una sottostringa r della stringa s può essere estratta come segue

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 matrice BC è in molti casi il risultato di funzioni di ricerca, ad es. sFind(), che possono restituire più riscontri nella stringa. Tramite l'indice sel è possibile estrarre direttamente la corrispondente parte di testo.

Esempio:​

// 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;

Estrazione dell'inizio e della fine della stringa "sLeft", "sRight"​

L'inizio b e la fine e della stringa s, di lunghezza l, possono essere ottenuti come copia nel modo seguente

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

Rimozione di una sottostringa "sErase"​

Per ottenere una copia di una stringa s da cui è stata rimossa una sottostringa si può utilizzare quanto segue

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 matrice BC è in molti casi il risultato di funzioni di ricerca, ad es. sFind(), che possono restituire più riscontri nella stringa. Tramite l'indice sel è possibile rimuovere direttamente la corrispondente parte di testo.

Inserimento di una stringa "sInsert"​

Per inserire una stringa t all'interno di una stringa s in corrispondenza della posizione b e restituire una copia r si può utilizzare quanto segue

r = sInsert(s, b, t);

Creare, formattare, leggere, ripulire​

Estrazione di valori da una stringa "sScan" 1​

Questa funzione estrae valori da una stringa s in base a una stringa di formato f:

v = sScan(f, s);

La stringa di formato f contiene segnaposto della forma %<x> (la lettera dopo % è arbitraria e non influisce sul tipo del risultato) e parti letterali che fungono da separatori nella stringa di origine. Per ogni segnaposto viene estratta la parte di testo compresa tra i letterali e convertita automaticamente nel tipo di dati appropriato.

// 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"
ComportamentoDescrizione
Ultimo segnaposto senza letterale di chiusuralegge fino alla fine della stringa
Virgolette attorno a un valorevengono rimosse automaticamente
Letterale della stringa di formato non trovatorestituisce cErr
Nessun segnaposto nella stringa di formatorestituisce cErr

Formattazione di una stringa "sFormat"​

Per rappresentare in forma formattata come stringa r una stringa f che contiene, ad es., valori numerici, si può utilizzare la funzione seguente

r = sFormat(f, ...);

Qui f rappresenta una stringa di formato del tipo printf() e per ogni segnaposto deve essere indicato un argomento corrispondente della forma %[<width>][.<precision>]<type>.

  • <width>: larghezza di campo opzionale per l'output, width < 0: allineato a sinistra

  • .<precision>: opzionale per f/g/e, numero di cifre decimali o di cifre significative

  • <type>: gli argomenti vengono convertiti in base al tipo di output scelto. Indicazioni aggiuntive sulla lunghezza del tipo di dati non sono quindi necessarie.

    <type>Tipo di datiOutput
    b<bool>Output di 'false' o 'true'
    d<int>Numero intero con segno, base 10
    u<uint>Numero intero senza segno, base 10
    x, X<uint>Numero intero senza segno, base 16
    cifre A-F minuscole (x) o maiuscole (X)
    o<uint>Numero intero senza segno, base 8
    f<dbl>Numero in virgola mobile senza esponente in base 10
    Esempio: 1234.5678
    g<dbl>Numero in virgola mobile in rappresentazione ottimizzata
    come f o e a seconda dell'ordine di grandezza del numero.
    Esempi: 1234.45678, 1.2345e9, 1.2345e-12
    e<dbl>Numero in virgola mobile con esponente in base 10
    Esempio: 1.2345678e3
    s<str>Testo

Esempio:​

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';

Accesso al contenuto di una risorsa "sResource"​

La funzione restituisce il contenuto della risorsa indicata come stringa costante (binaria).

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

A seconda della configurazione, il contenuto della risorsa può comprendere non solo puro testo UTF-8 (ad es. un file INI o un oggetto JSON), ma anche dati binari, come array double, immagini jpg, ecc. In particolare i dati binari possono essere elaborati ulteriormente solo da apposite funzioni speciali. Per l'implementazione di tali funzioni, siamo a vostra disposizione.

Rimozione degli spazi bianchi "sTrim"​

Questa funzione rimuove tutti gli spazi bianchi (whitespace) all'inizio e alla fine dell'argomento, come ad es. in

s_trimmed = sTrim(s);

Conversione in maiuscolo/minuscolo "sUpper", "sLower"​

La conversione di una stringa in maiuscolo o minuscolo avviene mediante

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

Semplificazione "sSimplify" delle stringhe​

La funzione sSimplify() sostituisce tutte le occorrenze multiple di spazi bianchi (spazi, tabulazioni, CR, LF, ...) con un singolo spazio.

s_simple = sSimplify(s);

Normalizzazione "sNormalize" delle stringhe​

La funzione sNormalize() rimuove le virgolette corrispondenti "..." o '...' all'inizio e alla fine della stringa e sostituisce tutte le sequenze di ESCAPE \ con il codice indicato.

s_normalized = sNormalize(s);

Cercare, trovare e scomporre​

Ricerca di sottostringhe "sFind"​

La funzione di ricerca sFind restituisce l'indice r oppure una matrice con posizione e lunghezza delle parti di testo trovate del modello p nella stringa s e può essere utilizzata come segue

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>
});

Se non viene trovato alcun modello, questa funzione restituisce -1.

Una matrice con i risultati della ricerca ha la struttura seguente:

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]

Questa matrice può essere passata direttamente, insieme al numero di riga del singolo risultato, alle funzioni sCopy() o sErase().

Un singolo risultato può essere elaborato ulteriormente con la funzione GetRow() oppure indicando direttamente l'indicizzazione:

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
ProprietàValoreDescrizione
pattern<str>Modello di ricerca costante, se il parametro p non viene utilizzato.
È un po' più performante per le modalità regex, perché l'espressione non deve essere tradotta ogni volta da capo.
case<bool>Ricerca con distinzione tra maiuscole e minuscole, (def: false, case insensitive)
all<bool>Restituisce un vettore con le posizioni iniziali e le lunghezze delle parti di testo corrispondenti,
non in combinazione con subex
regex<bool>Interpreta il modello pattern o p come espressione regolare, il risultato è una matrice con posizione e lunghezza delle espressioni/sottoespressioni trovate
subex<bool>Restituisce posizione e lunghezza delle parti di testo estratte in una matrice di risultati,
imposta automaticamente regex

Esempi​

// 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;

Sostituzione di sottostringhe "sReplace"​

Per sostituire (più) stringhe t_k all'interno della stringa s con i rispettivi testi corrispondenti s_k si può utilizzare quanto segue

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

La sostituzione avviene in modo sequenziale nell'ordine degli argomenti; i valori s_k vengono convertiti implicitamente in una rappresentazione testuale. Per avere più controllo sulla conversione si può utilizzare la funzione sFormat().

Esempio:​

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';

Ricerca di una combinazione chiave-valore "sGetKV" 1​

Questa funzione cerca la chiave k in una stringa (blocco di testo) s e restituisce il valore corrispondente. La ricerca non distingue tra maiuscole e minuscole.

v1 = sGetKV(s, k);
// Optionaler Konfigurationsblock
vx = sGetKV(..., { format: <enum>
, filter: <regex>
, index: <uint>
});
ProprietàValoreDescrizione
format<enum>Definisce il formato del blocco di testo e imposta il filter standard appropriato. Valori possibili: json (predefinito), ini, xml_attr, xml_node
filter<regex>Sovrascrive il valore predefinito del formato: espressione regolare che — dopo il nome della chiave — cattura il valore corrispondente come gruppo di cattura (...)
index<uint>Seleziona l'N-esimo riscontro (a base 0, predefinito: 0). Utile quando una chiave compare più volte, ad es. con elementi XML ripetuti.

Se la chiave non viene trovata (o l'indice supera il numero di riscontri), la funzione restituisce cErr. Le virgolette attorno al valore trovato vengono rimosse automaticamente.

Varianti di formato​

FormatoSeparatoreEsempio tipico
json (predefinito): dopo l'eventuale virgoletta di chiusura{"key": "value", "count": 3}
ini=, valore fino a fine rigahost=localhost\nport=8080
xml_attr=, valore tra virgolette<device id="42" name="sensor"/>
xml_nodetag XML <key>…</key><voltage>3.3</voltage>

Elementi annidati e ripetuti​

sGetKV non valuta la profondità di annidamento. Nel caso di oggetti annidati (ad es. {"outer": {"inner": 1}}) index:0 individua la chiave esterna; una ricerca mirata di valori più in profondità richiede una valutazione in due fasi: prima estrarre il valore della chiave esterna, poi applicare di nuovo sGetKV a tale valore.

Gli elementi ripetuti con la stessa chiave (ad es. <val>10</val><val>20</val>) possono essere selezionati con index.

Esempi​

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*([^;]+)'});

Suddivisione di stringhe "sSplit"​

Per suddividere una stringa in corrispondenza di un carattere ch si può utilizzare la funzione sSplit. Essa restituisce una matrice a due colonne con tutte le posizioni iniziali e le lunghezze delle sottostringhe corrispondenti

r1 = sSplit(s, ch);
// Optionaler Konfigurationsblock
rx = sSplit(..., { trim: <bool>
});
pos = rx[0, 0];
len = rx[0, 1];
ProprietàValoreDescrizione
trim<bool>Rimuove gli spazi bianchi all'inizio e alla fine degli elementi

Numero di righe all'interno di una stringa "sLines"​

Il numero di righe di una stringa s può essere determinato come segue

lines = sLines(s);

Sono supportate tutte le varianti di interruzione di riga (LF, CRLF, LFCR, CR).

Estrazione di una riga da una stringa su più righe "sLine"​

Per estrarre l'i-esima riga da una stringa s è adatta la funzione seguente

lineI = sLine(s,i);
// Optionales Konfigurationsobjekt
lineX = sLine(..., { trim: <bool>
});
ProprietàValoreDescrizione
trim<bool>Rimuove gli spazi bianchi all'inizio e alla fine della riga

Lettura di righe complete "sGetLine"​

La funzione sGetLine() collega i singoli valori del canale stringa s e li memorizza finché non può essere restituita una riga completa. Questa viene rimossa dal buffer e con il resto che rimane l'accumulo prosegue.

Per ottenere una riga completa da un flusso di caratteri si può utilizzare quanto segue

line1 = sGetLine(s);
// Optionales Konfigurationsobjekt
lineX = sGetLine(..., { trim: <bool>
, eoln: <str>
, timeout: <dbl>
});
ProprietàValoreDescrizione
trim<bool>La riga restituita viene inoltre ripulita dagli spazi
eoln<string>Definizione del terminatore di riga
timeout<dbl>Tempo in secondi dopo l'ultimo frammento, trascorso il quale viene inserita una fine riga.

Footnotes​

  1. Disponibile dalla versione 13 del catalogo. ↩ ↩2