Contare caratteri contro un limite fissato da qualcun altro
Pubblicato il 10/08/2026 · 13 min di lettura · Strumenti testo e lingua
Daniel Okonkwo — Sviluppatore front-end e redattore Tech presso Allin
Performance web · Formati di file
Verificato su 4 fonti
«Carattere» non è una cosa sola, e chi ha scritto il limite ha deciso quale senza dirtelo. Il contatore di frequenza di questa pagina percorre la stringa con un iteratore di code point, quindi conta code point Unicode. Incollagli l'emoji della famiglia e restituisce cinque righe la cui somma fa sette: quattro righe per le quattro persone e una riga per qualcosa che non si vede affatto, il congiuntore a larghezza zero, con conteggio 3. La stessa stringa è 1 cluster di grafemi, 7 code point, 11 unità UTF-16 e 25 byte UTF-8. Quei quattro numeri sono ciò che quattro sistemi diversi chiamano la sua lunghezza, perciò una casella che dice 500 caratteri ne ammette 500 se conta grafemi, 71 se conta code point, 45 se usa il .length di JavaScript o il .length() di Java, e 20 se la colonna dietro è da 500 byte. Lo strumento non stampa alcun totale; la colonna la sommi tu, e le impostazioni predefinite saltano gli spazi e unificano le maiuscole, ed è per questo che «Merci beaucoup !» dà 11 righe che sommano 14 e non 16 caratteri. L'SMS è più severo. Il protocollo trasporta 140 ottetti, cioè 160 caratteri dell'alfabeto GSM a 7 bit oppure 70 in UCS-2, e scendono a 153 e 67 appena i messaggi vengono concatenati. Un solo carattere fuori dalla tabella a 7 bit ribalta l'intero messaggio: basta un apostrofo tipografico, basta una qualsiasi emoji, e bastano le á í ó ú spagnole o le ã õ portoghesi, perché la tabella predefinita semplicemente non le contiene. Le meta description non si contano affatto: gli snippet vengono troncati per larghezza resa, non per numero di caratteri.
Un'emoji vale 1 carattere, o 7, o 11, o 25, a seconda di chi conta. Quale intendono il tuo modulo, il tuo database e il tuo gateway SMS — e un test con un solo incolla per capire con quale hai a che fare.
Quattro numeri per una sola emoji
Prendi l'emoji della famiglia composta da un uomo, una donna, una bambina e un bambino. Sullo schermo è una cosa sola, un colpo di Backspace la cancella, e il cursore la scavalca in un passo. Sotto ci sono quattro emoji di persone separate da tre copie di un carattere di controllo invisibile, U+200D, il congiuntore a larghezza zero. Misurata in quattro modi, quella stringa è 1 cluster di grafemi, 7 code point, 11 unità UTF-16 e 25 byte UTF-8. Nessuno di quei numeri è sbagliato; rispondono a quattro domande diverse.
Il cluster di grafemi è il carattere così come lo percepisce l'utente, e Unicode definisce i confini tra essi in un allegato tecnico, l'UAX n. 29, proprio perché «ciò che un lettore considera un carattere» non è abbastanza ovvio da lasciarlo a ciascun programma. Il code point è la voce numerata del catalogo Unicode. L'unità UTF-16 è una casella da sedici bit, e tutto ciò che supera U+FFFF ne richiede due: è il numero che JavaScript, Java e C# restituiscono quando chiedi la lunghezza di una stringa. Il byte UTF-8 è ciò che viaggia davvero sulla rete e occupa una colonna di database.
Cosa conta esattamente questo strumento
Il contatore di frequenza percorre l'input con un ciclo for-of, che in JavaScript avanza per code point e non per unità da sedici bit. Conta quindi code point, e lo si può vedere all'opera. Incolla l'emoji della famiglia con le impostazioni predefinite e l'output è di cinque righe: una riga apparentemente vuota con conteggio 3, poi quattro righe con 1 ciascuna. La riga vuota è il congiuntore a larghezza zero. Somma la colonna e ottieni 7, cioè il numero di code point, non l'1 che risponderesti se ti chiedessero quanti caratteri hai incollato.
Due impostazioni predefinite cambiano il conto prima che tu lo veda. «Salta gli spazi» è attivo, quindi gli spazi non compaiono mai nella tabella: «Merci beaucoup !» ha 16 caratteri ma produce 11 righe che sommano 14, perché i due spazi cadono. Anche «Ignora maiuscole» è attivo e fonde le coppie, che è quasi sempre ciò che si vuole e ogni tanto produce qualcosa di strano. La İ maiuscola turca passa a minuscolo come una i più un punto combinante separato, così la tabella guadagna una riga la cui chiave è lunga due code point. Lo strumento non ha mai promesso che la chiave di riga fosse un solo carattere; è ciò che ha prodotto la conversione a minuscolo.
E non stampa alcun totale. L'output è una tabella a due colonne, carattere e conteggio, ordinata per conteggio e poi alfabeticamente, e il numero per cui probabilmente sei venuto è la somma della seconda colonna. Se vuoi i quattro conteggi affiancati senza fare calcoli, il contatore di byte UTF-8 del sito stampa grafemi, code point, byte UTF-8, unità UTF-16, parole e righe in un colpo solo: esiste proprio perché quei numeri divergono, e il suo stesso commento lo dice.
Il test con un solo incolla che rivela quale contatore hai davanti
Incolla un'emoji della famiglia nel campo dotato di contatore e leggi il contatore. Se dice 1, conta cluster di grafemi. Se dice 7, conta code point. Se dice 11, usa la lunghezza di stringa nativa del linguaggio, cioè unità UTF-16: JavaScript, Java o C#. Se dice 25, sta contando byte UTF-8 e il limite è in realtà un limite in byte. Quattro risposte possibili, quattro sistemi diversi dietro la casella, e il test sta in un incolla.
Il test ha una seconda metà, e pesa di più: il contatore che vedi nel browser non è necessariamente quello che decide. Un contatore lato client è quasi sempre il .length di JavaScript, mentre il rifiuto all'invio arriva da un server, da una definizione di colonna o da un'API a valle con una sua idea. Se il campo ti lascia scrivere 500 e il salvataggio fallisce a 480, i due capi contano in modo diverso e vince il più corto. Scrivi il testo, salva, ricarica la pagina e guarda cosa è tornato: un troncamento si vede più facilmente di quanto si preveda.
SMS: 160 caratteri, oppure 70, e a decidere è un apostrofo
Il servizio di messaggi brevi trasporta fino a 140 ottetti di dati utente. Impacchettali con l'alfabeto GSM a 7 bit predefinito e ci stanno 160 caratteri; codificali in UCS-2, due byte per unità, e ce ne stanno 70. Quando un messaggio è troppo lungo viene spezzato, e ogni parte cede spazio a una piccola intestazione che dice quale parte è: restano 153 caratteri a 7 bit o 67 unità UCS-2 per segmento. Nulla di tutto ciò è negoziabile, e ogni listino di SMS massivi è costruito su questo.
La parte interessante è cosa contiene quella tabella a 7 bit, perché un solo carattere che manchi ribalta l'intero messaggio in UCS-2 e più che dimezza la capacità. La tabella contiene un insieme generoso di accenti — è é ù ì ò à ä ö ü ñ å æ ø ß, più Ä Ö Ü Ñ É Å Æ Ø Ç — insieme a ¡ ¿ § e a una manciata di simboli monetari. Non contiene á, í, ó né ú, e non contiene ã né õ. Quindi un messaggio spagnolo con «está» o «aquí», o uno portoghese con «não», è un messaggio da 70 caratteri e non da 160, e nulla sullo schermo lo dice a chi invia.
La specifica lo aveva previsto e definisce tabelle nazionali: lo spagnolo ha una tabella a scorrimento singolo, il portoghese ne ha una a scorrimento singolo e una a scorrimento bloccato. Un carattere a scorrimento singolo costa due delle tue caselle a 7 bit invece di una, ed entrambi i capi devono implementare il meccanismo. In pratica la maggior parte dei gateway non ci prova e passa a UCS-2. Lo stesso meccanismo di escape spiega perché un piccolo insieme di simboli comuni costi già due caselle ciascuno in un messaggio normale: l'accento circonflesso isolato, le graffe, le quadre, la barra rovesciata, la tilde, la barra verticale e il simbolo dell'euro stanno nella tabella di estensione, non in quella principale. E l'apostrofo tipografico che il tuo elaboratore di testi ha inserito quando ne battevi uno dritto non sta in nessuna delle due.
La meta description si misura in pixel, non in caratteri
Ogni checklist SEO dà un intervallo di caratteri per la meta description. La documentazione di Google non ne dà nessuno: dice che non c'è limite di lunghezza, che lo snippet viene generato dalla pagina e talvolta dalla description, e che gli snippet vengono ritagliati per entrare nel risultato. Entrare è questione di larghezza resa: una description piena di lettere larghe viene tagliata prima di una della stessa lunghezza in caratteri fatta di lettere strette, e il risultato mobile ha meno spazio di quello da scrivania.
La conseguenza pratica non è abbandonare un budget di caratteri, ma smettere di trattarlo come una regola. Metti ciò che deve sopravvivere nella prima metà della frase, poi controlla il risultato reale invece del conteggio. E tieni presente che Google riscrive spesso la description per intero quando giudica che il contenuto della pagina risponda meglio alla query: una description troncata che non hai mai scritto è un problema diverso da una che hai scritto tu.
Due grafie della stessa parola, due lunghezze
C'è un'ultima trappola che con le emoji non c'entra nulla. La lettera é può essere un code point, U+00E9, oppure due: una e semplice seguita da un accento acuto combinante. Sembrano identiche, significano la stessa cosa e hanno lunghezze diverse: 1 code point e 2 byte contro 2 code point e 3 byte. Quasi tutte le tastiere producono la prima; alcuni sistemi, alcuni scanner e moltissimo testo copiato e incollato producono la seconda. Passa la forma scomposta nel contatore di frequenza e torna in due righe, una delle quali è un accento nudo appoggiato sul nulla.
Se un controllo di lunghezza fallisce su un testo che sembra della lunghezza giusta, è la prima cosa da provare. Normalizzare alla forma composta prima di contare lo risolve, ed è una sola chiamata in ogni linguaggio che includa una libreria Unicode. Fallo prima di contare, prima di salvare e prima di confrontare due stringhe per uguaglianza: la stessa parola in due forme di normalizzazione non è uguale in nessun confronto di byte.
| Unità di conteggio | L'emoji della famiglia conta come | Dove la incontri | Quanti entrano sotto «500 caratteri» |
|---|---|---|---|
| Cluster di grafemi (UAX n. 29) | 1 | Lo String.count di Swift; un colpo di Backspace; la prima riga del contatore di byte UTF-8 | 500 |
| Code point Unicode | 7 — quattro persone più tre congiuntori | Il len() di Python 3; le rune di Go; il contatore di frequenza di questa pagina | 71 |
| Unità di codice UTF-16 | 11 | Il .length di JavaScript, il .length() di Java, il .Length di C# — quasi tutti i contatori di modulo nel browser | 45 |
| Byte UTF-8 | 25 | Il len() di Go; una colonna o un header misurati in byte | 20 |
| Unità UCS-2 in un segmento SMS | 11 | Un singolo segmento da 70 unità, o 67 quando i messaggi sono concatenati | 6 per segmento — la settima apre un altro messaggio |
Domande frequenti
- Perché la tabella di frequenza ha una riga vuota?
- Perché un carattere che non si vede resta un carattere, e il contatore lo riporta onestamente. Nell'emoji della famiglia quella riga è U+200D, il congiuntore a larghezza zero, che compare tre volte: è ciò che incolla le quattro persone in un'unica immagine. I selettori di variazione si comportano allo stesso modo: il piccolo U+FE0F che trasforma un simbolo monocromatico in un'emoji a colori è invisibile e viene contato. Una riga vuota con un numero accanto è lo strumento che ti dice che il tuo testo contiene qualcosa che non vedi, cioè esattamente ciò che serve sapere prima di incollarlo in un campo con un limite.
- Una sola emoji dimezza davvero il mio SMS?
- Più che dimezzarlo. Un messaggio è codificato in un solo alfabeto da capo a fondo, quindi un unico carattere fuori dalla tabella GSM a 7 bit forza l'intero messaggio in UCS-2 e la capacità scende da 160 caratteri a 70. Con le emoji è peggio: tutto ciò che supera U+FFFF occupa due unità UCS-2, per cui una semplice faccina sorridente costa due dei tuoi 70 e l'emoji della famiglia ne costa undici. Sei di quelle emoji e una parola non entrano in un singolo segmento. Se la tua bolletta di SMS massivi è salita senza che il testo si allungasse, cerca un apostrofo tipografico o un accento che la tabella non porta prima di guardare altrove.
- Il mio modulo dice 500 caratteri. Quali 500 intende?
- Testalo invece di indovinare. Incolla un'emoji della famiglia e leggi il contatore: 1 significa cluster di grafemi, 7 code point, 11 unità UTF-16, 25 byte UTF-8. In ASCII puro i quattro coincidono, ed è per questo che la differenza salta fuori solo quando un utente reale incolla un nome accentato o un'emoji nel campo. Se il modulo è tuo, conta cluster di grafemi per il numero visibile e valida contro ciò che lo strato di archiviazione impone davvero, poi fissa il limite visibile al minore dei due. Se non è tuo, assumi la risposta più piccola possibile e lascia margine.
- Un VARCHAR(500) di database sono cinquecento byte o cinquecento caratteri?
- Nei database relazionali più diffusi la lunghezza dichiarata è in caratteri, non in byte — ma i limiti che le stanno attorno sono in byte, ed è lì che ci si incastra. Una riga ha una dimensione massima in byte, un indice ha una dimensione massima di chiave in byte, e una codifica a quattro byte per carattere moltiplica entrambe. Risultato: la colonna accetta i tuoi 500 caratteri e l'indice si rifiuta di essere creato. I limiti in byte sono più frequenti fuori dal database: valori di header HTTP, payload di code di messaggi, chiavi di object storage e moltissime API di terze parti sono specificate in byte. Quando la documentazione dice byte, conta byte.
- Quanti caratteri deve avere una meta description?
- Non esiste un numero documentato, e quello che ti hanno dato è stato misurato sui risultati di ricerca, non pubblicato come regola. L'indicazione di Google è che le description non hanno limite di lunghezza, che gli snippet sono tratti dalla pagina tanto quanto dalla description, e che vengono ritagliati per entrare — ed entrare è questione di larghezza resa in un impaginato che differisce tra telefono e scrivania. L'abitudine utile è caricare l'inizio: metti l'argomento, la cifra o l'elemento distintivo nella prima proposizione e considera tutto il resto sacrificabile. Poi guarda il risultato reale in una ricerca vera e regolati su ciò che vedi.
Articoli che potrebbero interessarti
Tutte le guide →Strumenti correlati
Questo descrive ciò che questi strumenti di testo fanno oggi, verificato eseguendo le loro stesse funzioni sugli input esatti qui citati. Dove uno strumento sbaglia un caso, la cosa è scritta anziché smussata, perché uno strumento imprevedibile è peggio di uno di cui si conoscono i limiti. Nulla di tutto ciò è una regola che uno strumento sia tenuto a seguire: le maiuscole, il conteggio dei caratteri e la numerazione delle righe sono convenzioni, e quelle convenzioni cambiano a seconda della lingua, del manuale di stile e del programma che sta dall'altra parte. Prima di passare uno di questi su un testo che non potrai ribattere, passa prima su una copia e confronta le due estremità.
Fonti
- Unicode Consortium — UAX #29, Unicode Text Segmentation — the grapheme cluster boundary rules that define a user-perceived character, including the treatment of zero-width joiners, variation selectors and emoji modifier sequences
- ETSI / 3GPP — TS 123 038 (3GPP TS 23.038) — the GSM 7-bit default alphabet table in clause 6.2.1, its escape-driven extension table in 6.2.1.1 (which holds the caret, braces, brackets, backslash, tilde, vertical bar and euro sign), and the national language single- and locking-shift tables for Spanish and Portuguese in 6.2.1.2 and Annex A
- ETSI / 3GPP — TS 123 040 (3GPP TS 23.040) — the transfer of short messages: the user data of an SM MT or SM MO carries up to 140 octets, which is what yields 160 seven-bit characters or 70 UCS-2 units per single message
- Google Search Central — Control your snippets in search results — no documented character limit for a description; snippets are generated from the page and from the description and are trimmed to fit the result
Hai notato un errore in questo articolo?