Furor Teutonicus blog | over | volg | teuto | lyme | archief | doneer | todo
🕰️
  ⬩  
✍️ Evert Mouw
  ⬩  
⏱️ 7 min

Tab Gescheiden Waarden en Elastische Tabstops

tab key on keyboard

Technologie is prachtig! Terwijl politici en bankiers er een rotzooi van maken zien we jaar na jaar weer nieuwe innovaties in de (informatie)technologie. Soms gaat het om kleine dingen. Vandaag ga ik het vooral hebben over de tab toets die op je toetsenbord zit; en wat je daarmee kunt doen.

Geschiedenis

Toen onze verre voorouders nog typemachines gebruikten moesten ze ook wel ’s tabellen met kolommen uittypen. Daarvoor had zo’n typemachine dan zgn. tabstops: op vaste horizontale posities kon de wagen (de rol met het papier) halt houden, zodat je op die posities kon beginnen met typen. Zo kon je mooi uitgelijnde kolommen typen.

Het toetsenbord voor computers is natuurlijk afgekeken van die typemachines. Zelfs in de codes waarmee tekst wordt opgeslagen in computerbestanden zie je die geschiedenis. De zgn. ASCII code voor tab is 9 en met Escape codes in programmeertalen wordt de tab door \t weergegeven.

Puur vanwege historische redenen is er ook nog een verticale tab, ascii code 11, escape code \v. De verticale tabs worden niet gebruikt in computers, en daarom heeft een programmeur genaamd James Hague een artikel geschreven met de titel Stop the Vertical Tab Madness.

Kolommen en tabellen, tab gescheiden waarden

De tab toets werd historisch dus gebruikt om tabellen te kunnen maken. De tabel is nog steeds de belangrijkste manier om gestructureerde data op te slaan. In de praktijk worden tabellen niet alleen in databases gebruikt, maar ook in rekenbladprogramma’s (spreadsheet applications) zoals Gnumeric en Excel.

Maar veel tekst- en rekenwerk gaat via specialistische programma’s of via command-line applicaties. Zeker in de Unix / Linux wereld en in de wetenschappelijke wereld. Zulke tekstgebaseerde programma’s zijn heel handig omdat je ze in een shell script (batch file) kunt gebruiken, en je ze gemakkelijk samen kunt laten werken via pipelining. Zie onderaan dit artikel het pipelining voorbeeld.

Daarom wordt data vaak niet in spreadsheet formaten maar in simpele tekstbestanden opgeslagen. Een bijkomend en belangrijk voordeel is dat ze zo simpel zijn dat ze overal kunnen worden ingelezen. Notepad is al genoeg om de data te kunnen zien.

Vaak worden zgn. CSV bestanden gebruikt: Comma Separated Value bestanden. Nadeel daarvan is dat gewone tekst vaak komma’s bevat. Daarom worden in plaats van komma’s soms puntkomma’s (;) gebruikt, of ook vaak tabs. Want wie gebruikt er nu tabs in gewone tekst? Tabs zijn bij uitstek geschikt als scheidingsteken in zulke tabel- of data-tekstbestanden.

Old-school Unix practice used to favor tabs, a preference reflected in the defaults for cut(1) and paste(1); but this has gradually changed as format designers became aware of the many small irritations that ensue from the fact that tabs and spaces are not visually distinguishable. — Delimiter Separated Value. The Art of Unix Programming, Eric Raymond, 2004.

Als je tabs gebruikt, noem het dan geen CSV bestand! Want het zijn dan niet langer komma-gescheiden waarden, maar tab-gescheiden waarden. Het is dan een TSV bestand: Tab Separated Values. Het Internet Assigned Numbers Authority (IANA) heeft er zelfs een MIME type voor: text/tab-separated-values .

TSV bestanden worden oficieel ondersteund door Google Drive en door Gnumeric, maar in de praktijk kunnen alle rekenblad toepassingen zoals Excel zulke bestanden openen. Alleen zullen Google Drive en door Gnumeric het wat soepeler doen. Vrijwel elke applicatie die CSV bestanden kan openen kan ook TSV bestanden openen en exporteren.

Hieronder zie je hoe Gnumeric mijn bestandje cijfers.tsv weergeeft. Ik moest nog wel een paar kolommen handmatig breder maken om een goede weergave te krijgen.

cijfers.tsv - Gnumeric

Maar gewoon in een simpele texteditor openen kan toch ook? Het probleem is dat er soms meerdere tabs nodig zijn om op dezelfde horizontale positie uit te komen. Kijk maar eens naar dit voorbeeld:

cijfers.tsv - Notepad2

Gelukkig is er een elegante oplossing als je geen spreadsheets wilt gebruiken: elastische tabstops.

Elastische tabstops voor TSV bestanden en programmacode

Programmeurs zijn vaak nogal met tabs bezig: om broncode overzichtelijk te houden zijn die tabs ook wel gemakkelijk. Met tabs kun je inspringen. Ingesprongen code voert een subtaak uit. Daarvoor is meteen zichtbaar welke code een onderdeel is van welke functie.

Maar omdat een aantal tabs niet altijd overeenkomen met een bepaalde positie zijn tabs niet altijd betrouwbaar. Sommige programmeurs gebruiken daarom gewoon spaties. Dat is natuurlijk wel wat minder elegant, en er is soms nogal wat verhitte discussie over, maar ziet er in ieder geval altijd hetzelfde uit zolang je maar fixed-with fonts gebruikt.

Nick Gravgaard kwam in 2006 op een briljant, simpel en elegant idee: elastische tabstops. De tabstops worden in zijn voorstel netjes uitgelijnd. Hij heeft zijn idee op zijn website beschreven in het duidelijke artikel Elastic tabstops – a better way to indent and align code. Hij heeft ook een geanimeerde afbeelding gemaakt om zijn idee te verduidelijken, en die afbeelding heb ik hieronder overgenomen:

columnblocks_coloured

Op dit moment zijn er nog niet veel code editors die deze elastische tabstops ondersteunen. Er is een plugin voor Gedit en voor Visual Studio 10. Mogelijk gaan in de toekomst veel Scintilla-gebaseerde editors zoals Notepad++ en Geany het ondersteunen omdat er een aanpassing voor Scintilla is. Markdown liefhebbers op de Mac kunnen MultiMarkdown Composer gebruiken. Maar eigenlijk is momenteel de enige out-of-the-box oplossing het programma Code Browser.

Code Browser toont mijn cijfertabel (TSV bestand) correct, en past tijdens het typen ook automatisch (elastisch) de tabstops aan.

Op mijn Windows PC heb ik .tsv bestanden geassocieerd met Code Browser. Ik ben er heel tevreden over.

Pipelining voorbeeld (Linux of Unix)

Dit valt niet meer onder het onderwerp “tabs”, maar was eerder in het artikel beloofd als extra uitleg…

Je hebt een lijstje met getallen in het bestand 12345.txt en die wil je optellen.

echo -n E | cat 12345.txt - | tr "\n" "+" | tr "E" "\n" | bc

Het bestand 12345.txt bevat de getallen 1 t/m 5, gescheiden door regeleinden (“newlines”, \n). Alle newlines worden vervangen door een plusje +. Hierdoor wordt er de tekststring “1+2+3+4+5” gemaakt. Daarnaast is er nog wat hocuspocus (in grijs om te zorgen dat op het laatst toch nog een regeleinde (newline) toegevoegd wordt, want dat wil bc graag. Met bc kun je rekenen, het is een soort programmeerbare rekenmachine. Als hij die som als invoer krijgt, zal hij de uitkomst (15) geven.


Aanvullingen (2013-06-09)

Nog wat aanvullingen naar aanleiding van een discusie over dit artikel op Facebook met Sjors.

Waarom geen CSV?

TSV is gemakkelijker te bewerken met behulp van elastic tabstops. Bovendien zijn veel CSV implementaties nogal mank:

In fact, the Microsoft version of CSV is a textbook example of how not to design a textual file format. Its problems begin with the case in which the separator character (in this case, a comma) is found inside a field. The Unix way would be to simply escape the separator with a backslash, and have a double escape represent a literal backslash. This design gives us a single special case (the escape character) to check for when parsing the file, and only a single action when the escape is found (treat the following character as a literal). The latter conveniently not only handles the separator character, but gives us a way to handle the escape character and newlines for free. CSV, on the other hand, encloses the entire field in double quotes if it contains the separator. If the field contains double quotes, it must also be enclosed in double quotes, and the individual double quotes in the field must themselves be repeated twice to indicate that they don’t end the field. — Delimiter Separated Value. The Art of Unix Programming, Eric Raymond, 2004.

XML is beter voor complexere situaties

Als je gestructureerde data hebt die geen tabel-structuur heeft, of als je meer uitgebreide meta-data en/of contraints gebruikt, of als je slimme tools wilt gebruiken die goed zijn in het overzetten van zulke data, dan zal XML vaak praktischer zijn. Zelfs Gnumeric, de spreadsheet applicatie die ondersteuning voor TSV ingebouwd heeft, slaat zelf zijn databestanden als XML op.

Het nadeel van XML is dat het meer opslag- en bandbreedte kost (maar XML is wel goed comprimeerbaar). Een ander nadeel is dat XML minder gemakkelijk in een texteditor te bewerken is, waardoor je dus meer bent aangewezen op tooling en libraries.

JSON als tussenoplossing

Als je net wat meer structuur wilt dan TSV kan bieden, maar niet de complexiteit van XML wilt, dan is JSON een goede tussenoplossing.

Het is een kwestie van smaak

Ik ben een aanhanger van de stijl die graag zo min mogelijk afhankelijk wil zijn van specifieke tools, en dus data simpel wil opslaan en met diverse simpele tools die data wil kunnen tonen en bewerken (flexibiliteit). Dat maakt TSV voor mij ook esthetisch meer elegant. Ik kan zowel een spreadsheet als een tekstverwerker gebruiken. XML is toch wat minder bewerkbaar in de tekstvorm. Wel is XML natuurlijk ideaal als je moet werken met wat meer complexe datastructuren of meer gecontroleerde data.


Deze blogpost werd in december 2022 overgezet van WordPress naar een methode gebaseerd op Markdown; het is mogelijk dat hierbij fouten of wijzigingen zijn ontstaan t.o.v. de originele blogpost.