Jupyter Notebook naar platte tekst: extractie zonder de stellage
Platte tekst is het juiste doel wanneer de bestemming geen mening heeft over opmaak. Een grep-pipeline, een diff, een zoekindex, een plagiaatcontrole, een e-mail in platte tekst aan een collega die geen bijlage wil — geen van die dingen wordt beter van backticks en hekjes, en verschillende ervan worden juist slechter van leestekens die iets betekenen voor een renderer en niets voor de lezer.
Deze converter neemt een .ipynb en geeft de woorden en de code terug, zonder toegevoegde opmaak. Cellen worden gescheiden door lege regels. Code verschijnt als code, zonder fences. Afgedrukte resultaten staan onder de cel die ze voortbracht, onder een simpel label Output:. Alles wat het JSON-formaat om die inhoud heen wikkelt gaat eruit. Het werk gebeurt in dit browsertabblad.
Het tokenargument
De meest voorkomende reden om een notebook plat te slaan, is dat er verderop iets per token rekent en dat een ruwe .ipynb een dure manier is om heel weinig te zeggen. Die verhouding is het waard om concreet te maken.
Een notebook met dertig cellen, waarvan de helft een grafiek produceert, komt routineus uit op twee of drie megabyte op schijf. De proza en de code erin zijn misschien acht kilobyte. De rest is base64-beelddata, HTML-duplicaten van resultaten die ook als platte tekst bestaan, en boekhouding per cel. Het ruwe bestand aan een model voeren kost niet alleen honderd keer meer dan nodig — meestal mislukt het gewoon, omdat het contextvenster volloopt met tekens die geen informatie dragen.
Erger nog: base64 tokeniseert beroerd. Gewone lopende tekst ligt rond de vier tekens per token. Een willekeurige base64-reeks bevat geen herhaalde deelstrings die het vocabulaire van de tokenizer kan comprimeren, dus die komt eerder uit op één token per twee tekens. Het nutteloosste deel van het bestand is tegelijk het deel met de slechtste verhouding tokens per teken. De teller hierboven laat het tokenaantal van het resultaat zien, zodat je ziet wat je werkelijk verstuurt.
Wat het platslaan overleeft
Structuur weghalen is niet hetzelfde als betekenis weghalen, en op die grens slaagt of faalt zulk gereedschap. Wat blijft:
- De inhoud van markdown-cellen, zoals geschreven. De tekens
#en**blijven staan, want in een markdown-cel zijn ze de enige aanwijzing die de auteur heeft voor nadruk en hiërarchie. Ze strippen zou een document dat al proza was platslaan tot ongedifferentieerde tekst. - Code, exact zoals getypt. Inspringing behouden, commentaar intact. De betekenis van Python hangt af van witruimte aan het regelbegin, dus dit is geen stijlkeuze.
- Tekstuele resultaten. Afgedrukte uitvoer, teruggegeven waarden, dataframe-previews in hun platte vorm.
- Foutnamen, meldingen en tracebacks, met de kleurcodes van de terminal eruit.
- Raw cells, waarin meestal LaTeX of reStructuredText staat die de auteur met rust wilde laten.
Wat verdwijnt: beeld- en videopayloads, PDF-bijlagen, de HTML-tweeling van elk resultaat dat ook als tekst bestaat, uitvoertellers, cel-id's, lege metadata-objecten, en cellen waar niets in staat. Een cel met alleen witruimte en zonder uitvoer is geen cel die iemand hoeft te lezen.
De kwestie van de figuurmarkering
Als een grafiek eruit gaat, moet er iets het gat markeren of juist niet. Er zit een echte afweging in. Laat je niets staan, dan leest de tekst schoon, maar verwijst een zin als “zoals de grafiek hierboven laat zien” nergens meer naar. Laat je een markering staan, dan heb je een regel toegevoegd die vrijwel geen informatie draagt.
Standaard blijft er één korte regel staan met het mediatype erin, en de schakelaar hierboven zet dat uit. Er zit een verwante subtiliteit aan vast die het weten waard is: matplotlib zendt naast de afbeelding een tekstrepresentatie uit, en die luidt altijd iets als <Figure size 640x480 with 1 Axes>. Naïef bewaard krijg je die regel en de markering achter elkaar, twee keer hetzelfde. Is een figuur weggehaald, dan wordt juist die tekst onderdrukt.
Afkappen vanuit het midden
Sommige uitvoer is lang omdat ze informatief is en sommige omdat er een lus in stond te printen. Het gereedschap kan het verschil niet zien, dus het maximeert elke uitvoer en snijdt uit het midden, houdt begin en eind, en meldt hoeveel tekens er zijn verdwenen.
Afkappen uit het midden wint van het alternatief om een specifieke reden: de twee informatiefste delen van een lange uitvoer zijn vrijwel altijd het begin, dat de vorm laat zien van wat er is geproduceerd, en het eind, dat laat zien waar het uitkwam. Een dataframe dat aan de staart is afgekapt toont je de eerste rijen en verbergt de samenvattingsregel. Aan de kop afgekapt verbergt het de kolomnamen. Het midden wegsnijden houdt beide uiteinden van het verhaal.
Praktische toepassingen van een plat notebook
Een paar dingen worden makkelijker zodra de JSON weg is. Twee versies van een notebook diffen in platte tekst laat zien wat er in de analyse is veranderd in plaats van welke uitvoertellers zijn opgehoogd — nbdime bestaat überhaupt alleen omdat een gewone git diff op een .ipynb onleesbaar is. Een map met notebooks doorzoeken op de functie die een grafiek bouwde wordt weer een gewone grep. Woorden tellen voor een rapport, een notebook door een tekst-naar-spraakprogramma halen, of methodologie plakken in een document dat geen Markdown rendert — het werkt allemaal zonder verdere opschoning.
Privacy, en waarom die hier structureel is
Notebooks zijn werkdocumenten, en werkdocumenten stapelen dingen op die niemand van plan was te bewaren: een token die tijdens het debuggen van een API even geplakt is, een connectiestring, twintig regels klantdata die zijn afgedrukt om een merge te controleren. Dat aan een conversiedienst geven is alles wat erin staat weggeven.
De parser hier is JavaScript dat in dit tabblad draait. Je bestand wordt door de browser gelezen, in het geheugen omgezet en weergegeven. Er is geen upload, dus is er geen bewaarbeleid om op te vertrouwen en niets om te laten verwijderen. Wil je liever fenced codeblokken en Markdown-koppen, dan doet de notebook-naar-Markdown-converter dat met dezelfde garantie.