Incollare una tabella in una pull request: che cosa si rompe, e i due caratteri che la rompono
Pubblicato il 29/07/2026 · 15 min di lettura · Strumenti per sviluppatori
Daniel Okonkwo — Sviluppatore front-end e redattore Tech presso OneKitly
Performance web · Formati di file
Verificato su 4 fonti
Una cella di tabella Markdown accetta tutto tranne due caratteri. La barra verticale chiude la cella, quindi va scritta \| — il convertitore lo fa per te: incolla USB-C | 2 m e restituisce USB-C \| 2 m, che GitHub mostra come una cella sola. L'a capo chiude la riga, e per lui non esiste alcun escape: una cella con un ritorno a capo vero è impossibile nella sintassi delle tabelle GFM, così lo strumento lo sostituisce con il tag HTML <br>, l'unica cosa che funziona. Sotto l'intestazione va la riga separatrice, ed è obbligatoria: una riga di intestazione senza una fila di trattini sotto non è una tabella, e GitHub la disegna come un paragrafo con delle barre. Quella fila porta anche l'allineamento: --- lascia il valore predefinito del motore, :-- allinea a sinistra, --: a destra, :-: centra, e due punti altrove non fanno nulla. La riga separatrice deve avere esattamente tante celle quante l'intestazione, altrimenti la tabella non viene riconosciuta affatto. Gli spazi che fanno quadrare le colonne sono puramente estetici: | a | b | e |a|b| producono un HTML identico byte per byte, da cui l'interruttore per allineare le colonne e il fatto che toglierlo sia innocuo. Un dettaglio sull'escape, perché qui l'output corretto sembra sbagliato: la barra rovesciata riceve l'escape prima della barra verticale. Una cella che contiene già x \| y esce come x \\\| y, dove \\ è una barra rovesciata letterale e \| una barra verticale letterale, così GitHub mostra l'unica cella x \| y. Fare l'escape solo della barra darebbe x \\| y — una barra rovesciata letterale seguita da un taglio di cella vero — e la colonna si spaccherebbe. È tutto nell'ordine, ed è il motivo per cui una tabella Markdown esistente può ripassare nel convertitore CSV e uscirne identica.
Una tabella Markdown vieta esattamente due caratteri dentro una cella: la barra verticale e l'a capo. Ecco che cosa fa ciascuno, come li tratta un convertitore, perché l'escape va applicato nell'ordine giusto, e perché il riempimento non conta mai.
Due caratteri, e due soltanto
Quasi tutto attraversa una cella di tabella Markdown senza danni. Accenti, ideogrammi, emoji, backtick, asterischi, parentesi quadre, simboli di valuta, virgolette: niente di tutto ciò significa alcunché per l'analizzatore di tabelle, che cerca sempre e solo due cose. La barra verticale chiude una cella. L'a capo chiude una riga. È tutta la grammatica, e ogni guaio che avrai incollando una tabella in una pull request sarà uno di quei due caratteri arrivato dove l'analizzatore non se lo aspettava.
La barra verticale ha un escape. Scrivi \| e l'analizzatore legge una barra letterale invece di un confine di colonna. Il convertitore lo applica per te: i suoi stessi dati di esempio contengono la cella USB-C | 2 m, e far passare l'esempio dà la riga | Câble | USB-C \| 2 m | 9.90 |, cioè una riga di tre celle e non di quattro. Dagli una cella che è soltanto una barra e ottieni \| da solo, sempre una cella. Questa parte è solida, ed è quella che le tabelle scritte a mano sbagliano più spesso: un comando di shell in una tabella di documentazione — ps | grep node — guadagna una colonna in silenzio e sposta ogni valore di un posto a destra, un difetto su cui un revisore scivola perché la tabella continua a sembrare una tabella.
L'a capo non ha escape, e questa è la parte da interiorizzare: una cella che contiene un ritorno a capo non è soltanto scomoda nella sintassi delle tabelle GFM, è impossibile. La riga finisce all'a capo, punto. Esistono esattamente due vie d'uscita oneste. Sostituire l'interruzione con il tag HTML <br>, che GitHub ammette dentro una cella e che il convertitore applica: un campo CSV fra virgolette che dice riga uno\nriga due esce come riga uno<br>riga due in una cella sola. Oppure accettare che quel contenuto non c'entra niente con una tabella e metterlo in un elenco o in un paragrafo sotto. Tutto il resto è illusione: non c'è trucco della barra rovesciata, né barra raddoppiata, né segno di continuazione.
La riga separatrice non è un ornamento
GitHub Flavored Markdown chiama la fila di trattini sotto l'intestazione la riga delimitatrice, e la specifica non lascia dubbi: è fatta di celle il cui unico contenuto sono trattini, con eventualmente due punti all'inizio, alla fine, o a entrambe le estremità. Senza di essa non c'è tabella. Una riga di intestazione e tre righe di dati senza trattini in mezzo compaiono come quattro paragrafi di testo con delle barre dentro — ed è per questo che una tabella che stava bene in un editor e si è rotta nella pull request ha quasi sempre perso proprio quella riga in un copia-incolla.
Quattro forme di cella separatrice significano quattro cose diverse, e il convertitore offre tutte e quattro come impostazione di allineamento. Un --- nudo lascia l'allineamento al motore, che in pratica vuol dire a sinistra in ogni motore che qualcuno usi. Due punti in testa, :---, forzano a sinistra. Due punti in coda, ---:, forzano a destra, ed è quello che vuoi su qualsiasi colonna di numeri. Due punti a entrambe le estremità, :---:, centrano. Due punti in mezzo ai trattini non sono un allineamento e non sono validi: la cella deve essere due punti, trattini, due punti, in quest'ordine, e nient'altro. Metti lo strumento su destra e una tabella a due colonne esce con | -----: | ---: | sotto, e ogni numero della colonna si allinea sull'ultima cifra nel risultato.
Una regola cattura la maggior parte dei fallimenti silenziosi: la riga separatrice deve avere esattamente tante celle quante l'intestazione, altrimenti la tabella non viene riconosciuta affatto. La specifica lo dice senza giri di parole, e il modo di guasto è il peggiore possibile: non ottieni una tabella rotta, non ottieni una tabella. Un'intestazione di quattro colonne sopra una separatrice di tre compare come testo letterale, barre comprese. È esattamente ciò che succede quando qualcuno aggiunge una colonna a mano e dimentica i trattini. Il convertitore non può commettere quell'errore perché costruisce entrambe le righe dallo stesso conteggio di colonne: un argomento decente a favore del generare la tabella invece di modificarla.
Il riempimento è per te, non per GitHub
Il convertitore ha un interruttore per allineare le colonne, attivo per impostazione predefinita, e non cambia nulla della tabella renderizzata. Attivo, una tabella a due colonne esce come | Item | Qty |, | ------ | --- |, | Widget | 3 |, con le celle squadrate. Disattivo ottieni | Item | Qty |, | --- | --- |, | Widget | 3 |, frastagliata. GitHub produce un HTML identico da entrambe. Gli spazi esistono perché un umano che legge il diff veda le colonne, e per nessun'altra ragione. Togli il riempimento quando la tabella è larga e ciò che verrà letto è il diff; lascialo quando il file si modifica a mano.
C'è una trappola da conoscere se i tuoi dati non sono latini. Il riempimento si calcola contando i caratteri, e un carattere non è una colonna. Dai al convertitore una cella con due emoji: ne conta due, riempie a due, e la sorgente non torna più in un editor dove ogni emoji occupa due colonne a larghezza fissa. Lo stesso accade con testo cinese, giapponese e coreano, e in senso opposto con una é scritta come e più accento combinante, che sono due caratteri in una colonna sola. Nulla di ciò tocca la tabella renderizzata, quindi è un problema di leggibilità e non di correttezza — ma se produci una tabella larga di toponimi giapponesi, non aspettarti una sorgente pettinata.
Fare l'escape dell'escape, e indovinare il delimitatore
Un convertitore che sostituisce ogni barra con \| e si ferma lì sbaglia su esattamente un input, ed è quello che si incontra appena si reimporta una tabella scritta da noi: una cella che contiene già \|. Fai l'escape solo della barra e x \| y diventa x \\| y, dove la barra rovesciata raddoppiata è una barra rovesciata letterale e la barra dietro torna viva: la colonna si spacca e nulla avverte. L'ordine deve essere l'opposto. Questo convertitore fa l'escape prima della barra rovesciata e poi della barra, così x \| y esce come x \\\| y, che sembra una barra rovesciata di troppo e non lo è: GFM legge \\ come una barra rovesciata letterale e \| come una barra verticale letterale, e mostra l'unica cella x \| y.
La conseguenza è che l'andata e ritorno è sicura. Converti dei dati in una tabella Markdown, tira fuori la tabella, salvala come CSV, rimettila dentro: le colonne che contenevano barre tornano come sono partite, e tutto il resto con loro. Vale più di quanto sembri, perché esportare una tabella renderizzata in un foglio di calcolo e reimportarla è una cosa ordinaria appena una colonna cambia nome. Lo strumento gemello di questo sito, il generatore di tabelle Markdown, chiude lo stesso anello dall'altro capo: il suo parser legge \| come una barra letterale quando il delimitatore è la barra e ne toglie l'escape in ingresso, così una tabella incollata lì torna identica anche lei.
Il delimitatore viene indovinato anziché dichiarato, e l'indovinello si fa su più record, non sulla sola intestazione. Lo strumento conta virgole, punti e virgola, tabulazioni e barre fuori dalle virgolette su un massimo di cinque record, e un delimitatore che dà lo stesso conteggio su ogni record letto batte quello che è soltanto più numeroso sul primo. È così che si risolve un'intestazione come A|B|C,D: da sola sembra tre colonne separate da barre, ma mettici sotto righe a virgole e vince la virgola, perché è il suo conteggio a ripetersi. Un export francese la cui intestazione è Nom;Prénom viene rilevato come punto e virgola in entrambi i casi. L'unica cosa che il primo record decide ancora da solo è quali delimitatori siano candidati: un'intestazione che non ne contiene nessuno dei quattro non lascia nulla da dirimere, e l'indovinello ripiega sulla virgola. Se la tua prima riga è insolita, imposta il delimitatore a mano.
Un flusso che sopravvive alla revisione
Esporta i dati come CSV invece di copiare celle da un foglio di calcolo, perché le regole di virgolettatura di un file CSV sono l'unica cosa che dice al convertitore dove finisce un campo con una virgola o un a capo. Incolla, controlla il separatore rilevato, scegli l'allineamento — a destra per i numeri, predefinito per il resto — e leggi le prime due righe di output prima di copiare. Quelle due righe sono l'intestazione e la riga separatrice, e se hanno un numero diverso di barre a valle non si renderizzerà nulla.
Poi cerca le tre celle che danno guai. Tutto ciò che contiene una barra: controlla che sia uscita come \| e non come un confine di colonna vivo, e ricorda che una cella che conteneva già una barra rovesciata se la vede raddoppiare: \\\| è l'output giusto, non un escape di troppo. Tutto ciò che era multiriga: controlla che sia diventato <br> e decidi se è davvero ciò che vuoi in una tabella. Tutto ciò che è vuoto: una cella vuota è perfettamente legale e appare vuota, quindi una riga di bianchi in mezzo alla tabella è un dato, non un danno. Se la tabella finisce in un repository e non in un commento, committala una volta con il riempimento attivo perché il primo revisore legga il diff, e poi non riformattarla mai più: una modifica di soli spazi su una tabella sono trenta righe di rumore in una pull request che non dicono nulla.
| Contenuto della cella | Che cosa emette lo strumento | Risultato |
|---|---|---|
| USB-C | 2 m | USB-C \| 2 m | Corretto — una cella con una barra visibile |
| Un campo fra virgolette con un vero a capo | riga uno<br>riga due | Corretto — l'unica cosa che le tabelle GFM permettono; un a capo vero è impossibile |
| x \| y (già con escape) | x \\\| y | Corretto — la barra rovesciata riceve l'escape per prima, GitHub mostra l'unica cella x \| y |
| Un campo vuoto | Niente fra le barre | Corretto — una cella vuota è legale e appare vuota |
| Una riga con meno campi dell'intestazione | Riempita con celle vuote fino alla riga più larga | Corretto — una tabella irregolare non renderizzerebbe affatto, quindi lo strumento la squadra |
| Due emoji | Riempita come se fosse larga due colonne | Solo estetico — ne occupano quattro; la tabella renderizzata non ne risente |
Domande frequenti
- Posso mettere un a capo dentro una cella di tabella Markdown?
- Uno vero no. L'a capo è ciò che chiude una riga, quindi la sintassi delle tabelle non ha modo di esprimere una cella che ne contenga uno: non esiste una sequenza di escape come \| per la barra. Il rimedio che GitHub accetta è il tag HTML <br>, ed è ciò che questo convertitore sostituisce: un campo CSV fra virgolette con un'interruzione diventa una cella che dice riga uno<br>riga due. Due limiti onesti. I motori che filtrano l'HTML mostreranno il tag come testo letterale, e una cella con tre o quattro <br> dentro di solito segnala che il contenuto vuole essere un elenco sotto la tabella e non una cella dentro di essa.
- La mia tabella appare come testo semplice con delle barre. Che cosa ho rotto?
- Quasi sempre la riga separatrice. O manca del tutto, o ha un numero di celle diverso dall'intestazione: la specifica esige che l'intestazione corrisponda alla riga delimitatrice nel numero di celle, e in caso contrario la tabella non viene riconosciuta e ricade su un paragrafo. Conta le barre sulla riga uno e sulla riga due della tua tabella; devono essere uguali. L'altra causa frequente è una riga vuota fra intestazione e separatrice, che chiude il blocco prima che cominci. Una terza, più rara: le celle separatrici possono contenere soltanto trattini e due punti facoltativi ai bordi, quindi uno spazio-trattino-spazio smarrito o una lineetta lunga incollata dalla correzione automatica di un editor invalida la riga.
- Contano gli spazi che allineano le colonne?
- No. | a | b | e |a|b| producono lo stesso HTML su GitHub, e l'interruttore per allineare le colonne esiste solo perché la sorgente si legga in un editor. Il riempimento ha però un costo reale in un repository: poiché la larghezza di ogni colonna è quella del suo valore più lungo, modificare una cella può cambiare il riempimento dell'intera colonna, e una modifica di una parola diventa un diff che tocca ogni riga. Se la tabella vive in un file versionato e cambia spesso, generarla senza riempimento dà diff più puliti. Se è scritta una volta e letta da umani nel file grezzo, tieni il riempimento.
- Posso usare grassetto, link o codice dentro una cella?
- Sì — la formattazione in linea funziona normalmente dentro le celle, quindi **grassetto**, un [link](https://example.com) e uno `snippet di codice` si renderizzano tutti. I costrutti di blocco no: né titoli, né elenchi, né blocchi di codice delimitati, né tabelle annidate, perché tutti richiedono a capo che la riga non può contenere. La trappola è uno snippet di codice con una barra, come `ps | grep node`. I backtick non proteggono una barra dall'analizzatore di tabelle — la cella viene divisa prima e il codice interpretato dopo — quindi devi comunque scrivere `ps \| grep node`. È uno dei pochi casi in cui l'escape va fatto a mano, perché il convertitore fa l'escape solo delle barre che vede nei dati di origine.
- Perché il mio CSV francese è uscito in una sola colonna?
- Perché la riga di intestazione non ha dato nulla da contare al rilevatore, ed è l'intestazione a decidere quali delimitatori siano perfino in gara. Lo strumento conta virgole, punti e virgola, tabulazioni e barre fuori dalle virgolette sui primi record, e un conteggio che si ripete batte quello che è soltanto il più grande alla riga uno; ma un delimitatore che nel primo record non compare non è nemmeno candidato. Un foglio di calcolo francese o tedesco esporta con punti e virgola, dato che la virgola è il separatore decimale, e un'intestazione Nom;Prénom viene rilevata bene. Un'intestazione di una sola parola senza separatore no: non c'è nulla da contare, l'indovinello ripiega sulla virgola e l'intero file arriva come una colonna sola. Imposta a mano l'opzione Delimitatore su Punto e virgola. Lo stesso rimedio vale per un export tabulato incollato da un terminale, dove le tabulazioni possono essere diventate spazi per strada e davvero non resta più alcun delimitatore da trovare.
Articoli che potrebbero interessarti
Tutte le guide →Strumenti correlati
Questo descrive il comportamento di un formato di file e di un motore di rendering, verificato sulla specifica citata e sul codice dello strumento così com'è oggi. I motori non concordano: GitHub, GitLab, un generatore di siti statici e l'anteprima del tuo editor sono quattro implementazioni diverse, e ciò che funziona in una può non funzionare in un'altra. Niente qui è una garanzia sulla tua catena di pubblicazione: prova il risultato dove verrà davvero pubblicato, e tratta ogni strumento, questo compreso, come qualcosa da verificare e non da credere.
Fonti
- GitHub — GitHub Flavored Markdown Spec, version 0.29-gfm (2019-04-06), section 4.10 Tables (extension): the delimiter row consists of cells whose only content are hyphens with optional leading or trailing colons; the header row must match the delimiter row in the number of cells or the table is not recognised; a table with no body rows generates no tbody
- GitHub Docs — Organizing information with tables: the pipe must be escaped as \| inside a cell, cells can carry inline formatting and links, and the vertical bars of a row need not line up
- RFC Editor — RFC 4180, Common Format and MIME Type for Comma-Separated Values (CSV) Files, October 2005 — section 2 rules 5 to 7: a field containing the delimiter, a line break or a double quote must be enclosed in double quotes, and an embedded double quote is written twice
- CommonMark — CommonMark Spec version 0.31.2 (2024-01-28): the core specification defines leaf and container blocks and contains no table construct — pipe tables are an extension, which is why a table that renders on GitHub may not render in a strict CommonMark processor
Hai notato un errore in questo articolo?