Tekst gebruiken in code
Zie Scherp Scherper - Hoofdstuk 3
Foto: Lalieka, CC BY-SA 4.0, via Wikimedia Commons
Welkom in de drukkerij
Een drukker zette vroeger elke tekst letter per letter, met loden letters uit een kast.
Een computer doet nog altijd hetzelfde: tekst is een rij losse tekens.
Voor er computers waren, zette een drukker een tekst letter per letter. Elke letter was een blokje lood, en alle letters lagen netjes gesorteerd in de vakjes van een zetkast. Voor elk woord haalde hij de letters een voor een uit hun vakje en zette ze naast elkaar. Een computer werkt nog altijd zo: elk teken heeft zijn vaste plaats in een tabel, en een tekst is een rij van die tekens. Die zetkast komt in dit hoofdstuk nog een paar keer terug.
Wat leer je in dit hoofdstuk?
Na dit hoofdstuk kan je:
het verschil tussen char en string uitleggen
ASCII en UNICODE situeren en weten hoe .NET tekst bewaart
\ escape characters (\n, \t, \", …) gebruiken en weten waarom een Enter uit twee tekens bestaat
@ tekst letterlijk laten staan met het verbatim teken @ of met een raw string literal (""")
tekst samenvoegen en formatteren met string interpolation ($)
speciale UNICODE-tekens en emoji op het scherm tonen
info over de machine ophalen via Environment en je programma afsluiten met een exitcode
Alles is een char
Elk teken dat je intypt is een char
Je toetsenbord toont maar een fractie van alle mogelijke tekens (vergelijk met een Spaans, Tunesisch of Chinees toetsenbord)
Voor we tekst inlezen, moeten we begrijpen hoe een computer al die tekens voorstelt.
ASCII: elk teken een getal
Een afspraak die bepaalt welk teken bij welke waarde hoort
Iedereen die ASCII volgt, kan berichten met die tekens naar elkaar sturen
Maar 128 tekens , want 7 bits
Oorspronkelijk gemaakt om via de Telex te communiceren
De ASCII-tabel
De eerste 32 tekens zijn “onzichtbare” stuurtekens: commando’s om oude typemachines aan te sturen (line feed , bell , form feed , …).
UNICODE: de opvolger van ASCII
Door de verdere digitalisering bleek ASCII al snel te klein
UNICODE heeft plaats voor meer dan 1 miljoen tekens: elke letter, smiley en pictogram, wereldwijd op dezelfde manier
De eerste 128 tekens zijn die van ASCII, dus beide zijn compatibel
UNICODE geeft elk teken een nummer : € is 8364, op elke computer
Hoe dat nummer als bytes bewaard wordt, is een aparte afspraak: de encoding (UTF-8, UTF-16, …)
Eén kastje, een hele muur
Terug naar de drukkerij. ASCII is één klein kastje: 128 vakjes, genoeg voor het Engelse alfabet, de cijfers en wat leestekens. Voor een é, een ñ of een Chinees teken is er geen vakje. UNICODE is een hele muur vol kasten, met ruimte voor meer dan een miljoen tekens. En de eerste kast van die muur is precies het oude ASCII-kastje: daarom is UNICODE compatibel met ASCII.
Char
char eenLetter = 'X' ;
Console. WriteLine ( eenLetter);
'X' Één enkel karakter, tussen apostrofs
Elke char is 16 bits groot: .NET bewaart tekst in het geheugen als UTF-16
UTF staat voor UNICODE Transformation Format , het getal is het aantal bits per blokje. In het geheugen gebruikt .NET UTF-16, naar het scherm gaat tekst vaak als UTF-8. Dat verschil komt terug bij het euroteken.
'7' is geen 7
char eenGetal = '7' ;
Console. WriteLine ( eenGetal + 1 );
'7' is een teken , geen getal
In de char zit de UNICODE-waarde van dat teken: 55 (kijk maar in de ASCII-tabel)
Reken je ermee, dan reken je dus met 55, niet met 7
Wil je met een cijfer rekenen, dan moet je het eerst converteren naar een getal. Dat zien we in hoofdstuk 4.
Wat zit er in het kluisje?
Vraag het eerst aan de zaal voor je verder klikt: wat zit er in het kluisje van letter? Geen A, maar het getal 65. Een computer bewaart enkel getallen. Pas wanneer je de char toont, wordt in de tabel opgezocht welk teken bij 65 hoort, en dan staat er een A op het scherm.
De tabel zegt enkel wélk teken het is. Hoe die A eruitziet, bepaalt het lettertype.
String
Een string is een reeks van 0, 1 of meer char-elementen.
'H' een char gebruikt een apostrof
"Hallo" een string: tekst staat tussen dubbele aanhalingstekens
In hoofdstuk 8 ontdek je dat een string eigenlijk een array van chars is, en leer je de string-methodes (ToUpper, Trim, Replace, …).
Drie keer “1”, drie types
char eenKarakter = '1' ;
string eenString = "1" ;
int eenGetal = 1 ;
Console. WriteLine ( eenKarakter);
Console. WriteLine ( eenString);
Console. WriteLine ( eenGetal);
Driemaal een 1 onder elkaar, maar telkens een ander type . Boeiend programma, hoor.
Wat zijn escape characters?
Niet de boeiendste materie , maar wie ze beheerst, tovert mooiere tekst op het scherm.
Sommige tekens hebben een speciale functie :
bv. " begrenst een string
bv. \' begrenst een char
Met een backslash (\) zeg je: behandel het volgende teken letterlijk. Dit heet een escape character .
Het probleem: hoe print je een aanhalingsteken?
char weglatingsteken = '''; // VS raakt volledig in de war
Escape characters to the rescue:
char weglatingsteken = '\'' ;
De belangrijkste escape characters
\' apostrof
\" aanhalingsteken
\\ backslash
\n nieuwe lijn (enter / newline)
\t horizontale tab
\uxxxx teken met hexadecimale UNICODE-waarde xxxx
Niet vanbuiten leren
in de praktijk grijp je vooral naar \n, \t, \" en \\. De rest zoek je op.
\a laat de computer biepen. In Windows Terminal en standaard ook op Linux en Mac hoor je niets: het teken wordt genegeerd. Je code is dus niet stuk.
Van de schrijfmachine
Veel van die escape characters zijn overblijfselen van de schrijfmachine en de telex. Met de hendel links schoof je de wagen terug naar het begin van de regel: de carriage return, De rol draaide het papier een regel verder: de line feed, . De tabtoets sprong naar de volgende tabstop, En het belletje heet in de tekentabel nog altijd bell, .
Escape in strings
string woord = " \' s avonds" ;
Om code op het scherm te tonen:
Console. WriteLine ( "Console.WriteLine( \" Cool he \" );" );
Console.WriteLine("Cool he");
Witregels en tabs
string eenString = "Een zin. \t na een tab \n Dan een nieuwe regel" ;
Console. WriteLine ( eenString);
Een zin. na een tab
Dan een nieuwe regel
\t springt naar de volgende vaste tabstop , handig om data uitgelijnd in een tabel te zetten.
De entertoets: \n en \r
Duw je op Enter , dan gebeuren er historisch twee dingen. De termen komen van de typemachine:
\r\n of \n?
\r\n Windows schrijft een nieuwe regel als \r\n
\n Linux en macOS gebruiken enkel \n
Console. Write ( $"Eerste regel{Environment.NewLine}Tweede regel" );
Eerste regel
Tweede regel
Environment.NewLine kiest zelf het juiste teken voor het systeem waarop je code draait. In je console volstaat \n; zodra je naar een bestand schrijft of over het netwerk verstuurt, begint het verschil te tellen.
Het verbatim teken @
Het apenstaartje @ voor een string zegt: behandel alles letterlijk
escape characters worden genegeerd
string zonderAt = "C: \\ Temp \\ Myfile.txt" ;
string metAt = @"C:\Temp\Myfile.txt" ;
Een aanhalingsteken schrijf je in een verbatim string als "", niet als \": @"Hij zei ""hallo"" in C:\Temp"
Console. WriteLine ( metAt);
Console. WriteLine ( @"Regel 1 \n Regel 2" );
C:\Temp\Myfile.txt
Regel 1\nRegel 2
@ en $ samen
string naam = "Finkelstein" ;
Console. WriteLine ( $@"Je bestanden staan in C:\Users\{naam}\Documents" );
Je bestanden staan in C:\Users\Finkelstein\Documents
Zonder @ compileert dit niet: \U en \D zijn geen geldige escape characters.
String interpolation met $
Zet een $ voor de string en alles tussen { } wordt als code uitgevoerd:
int leeftijd = 13 ;
string naam = "Finkelstein" ;
string zin = $"Ik ben {naam} en ik ben {leeftijd} jaar." ;
Je kende dit al uit hoofdstuk 1: op de plek van {naam} komt de inhoud van de variabele.
Expressies in interpolatie
Tussen de accolades mag elke expressie :
string a = $"Ik ben {leeftijd + 4} jaar." ; // 17
string b = $"Je naam telt {naam.Length} tekens." ; // aantal tekens
Console. WriteLine ( $"3 maal 9 is {3 * 9}" ); // 27
De expressie
{leeftijd + 4}
dan in de tekst geplaatst
Ik ben 17 jaar.
:C rekent niets om
double prijs = 12.34 ; // in euro
Console. WriteLine ( $"{prijs:C}" );
JP ¥12: de centen zijn weg
Vastzetten, bovenaan je Main:
System. Globalization . CultureInfo . CurrentCulture =
new System. Globalization . CultureInfo ( "nl-BE" );
:C zet enkel een munteenheid bij het getal, het rekent niets om. Dezelfde prijs in euro staat op een Amerikaanse pc als dollar op het scherm. De yen kent geen centen, dus een Japanse pc rondt af naar ¥12.
Met de lijn bovenaan Main toont het programma op elke computer € 12,34. Die lijn bepaalt ook hoe double.Parse invoer leest (H4): ook een gebruiker met Engelse instellingen moet dan een komma typen.
De +-operator op strings
+ plakt strings aan elkaar (concatenatie ):
string zin = "Ik ben " + naam + " en ik ben " + leeftijd + " jaar." ;
Zelfde resultaat, maar je let zelf op de spaties en de zin valt in stukken
$ Voor zulke zinnen: interpolatie
Wanneer wél +?
Lange tekst over meerdere lijnen , met + op het lijneinde:
Console. WriteLine ( "Je wordt wakker in een donkere kamer. " +
$"Het enige licht komt van een scherm, {naam}. " +
"Typ START om te beginnen." );
Elk stuk met accolades heeft zijn eigen $ nodig. Een $ op de eerste lijn geldt niet voor de rest.
Tekst stap voor stap opbouwen met tekst += stuk; (komt terug bij herhalingen, H6).
Opletten met de volgorde bij +
Bij + met strings en getallen door elkaar, van links naar rechts:
Console. WriteLine ( "1" + 1 + 1 );
Console. WriteLine ( 1 + 1 + "1" );
Console. WriteLine ( "1" + ( 1 + 1 ));
Zodra een string meedoet, is het resultaat een string.
Van links naar rechts, haakjes gaan voor.
Volgorde bij +, stap voor stap
De linkse operand bepaalt het resultaat bij twijfel: "1" + 1 wordt "11", en dat stuk is dan de linkse operand voor de volgende stap.
De char-val: ‘A’ + ‘B’
char letter1 = 'A' ;
char letter2 = 'B' ;
Console. WriteLine ( letter1 + letter2);
Op het scherm: 131, niet “AB”.
Een char bewaart een getal: A = 65, B = 66. De +-operator bestaat niet voor char, dus C# rekent met int: 65 + 66 = 131 .
Terug naar de kluisjes
Dezelfde kluisjes als daarnet. De + leest de 65 en de 66 uit de twee kluisjes en telt ze op: 131, en dat is een int, geen char. Een int toont Console.WriteLine als getal. Die 131 wordt dus nooit in de tabel opgezocht, en er verschijnt geen letter.
Bovenkast en onderkast
In de drukkerij lagen de letters in twee kasten boven elkaar. Bovenaan de bovenkast met de hoofdletters, daaronder de onderkast met de kleine letters. In het Engels heet dat de upper case en de lower case, en zo komen we aan “uppercase” en “lowercase”. Ook in de tekentabel liggen de hoofdletters en de kleine letters apart: A is 65, a is 97. Waarom net dat verschil, zie je op de volgende slide.
Waarom net 32?
Console. WriteLine ( 'a' - 'A' );
32
plaatsen tussen elke hoofdletter en zijn kleine letter.
Hoofdletter maken? Zet dat ene bitje uit.
Daarom koos ASCII in 1967 voor precies 32 plaatsen verschil.
Dat een char eigenlijk een getal is, hebben de makers van ASCII slim gebruikt. De eerste versie uit 1963 had nog geen kleine letters. Toen die er in 1967 bijkwamen, kreeg elke kleine letter een plaats precies 32 verder dan zijn hoofdletter: A is 65, a is 97.
Die 32 is met opzet gekozen. Binair is het verschil één enkel bitje. Een computer van toen zette een tekst in hoofdletters door bij elke letter dat ene bitje uit te zetten. UNICODE nam de eerste 128 tekens van ASCII over, dus ook in C# klopt het nog.
Vreemde tekens in console tonen
Speciale UNICODE-tekens tonen
Zet als allereerste lijn in Main, nog voor je iets naar het scherm stuurt:
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
Zet je die lijn later, dan kan tekst die je daarvoor al toonde verkeerd verschijnen.
Ook het euroteken bij {bedrag:C} heeft die lijn nodig. Een consolevenster op Windows werkt standaard met 256 tekens en daar zit de € niet in.
Wat is 0x?
UNICODE-tabellen geven hun codes hexadecimaal : tellen met zestien cijfers, 0 tot 9 en dan A tot F. In C# zet je er 0x voor.
'A' = 65
0x41
4 × 16 + 1 = 65
'©' = 169
0xA9
A (= 10) × 16 + 9 = 169
Hetzelfde getal in het kluisje, enkel anders opgeschreven.
De 0x-notatie zagen ze al bij de literals in het vorige hoofdstuk, maar daar bleef het bij de schrijfwijze. Hier de link: 'A' is 65, en 65 is hexadecimaal 41. De tabellen op symbl.cc en de \u-notatie werken altijd met die hexadecimale vorm, vandaar dat we hem vanaf nu in de code zien.
Drie manieren, één teken
Zoek de hexadecimale waarde op in een UNICODE-tabel (symbl.cc ), voor © is dat 00A9:
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
Console. WriteLine ( "©" ); // 1. het teken zelf plakken
char copyright = ( char ) 0x00A9 ; // 2. de code casten naar char
Console. WriteLine ( copyright);
Console. WriteLine ( "\u00A9" ); // 3. de \u-notatie in een string
Manier 2 is het kluisje van daarnet, maar omgekeerd: je steekt zelf het getal 0x00A9 (169) in het kluisje, en pas bij het tonen wordt daar een © van.
En emoji?
Een char gaat maar tot 0xFFFF, en \u verwacht exact vier cijfers. Emoji zitten daarboven. Oplossing? \U i.p.v. \u, en acht cijfers. Of plak de emoji gewoon in je string:
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
char blij = ( char ) 0x1F600 ; // compileert niet
Console. WriteLine ( "\U0001F600" ); // happy face!
Console. WriteLine ( "😀" ); // ook goed: gewoon plakken
.NET bewaart zo’n teken als twee 16-bit stukjes (een surrogate pair ). Eén emoji telt daardoor als 2 in string.Length. Die .Length is dus niet altijd het aantal zichtbare tekens.
Wat komt er door?
Console. WriteLine ( "A é € ╔ 😀" );
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
Console. WriteLine ( "A é € ╔ 😀" );
Laat de zaal eerst per teken voorspellen wat er verschijnt, en klik dan pas.
Zonder de UTF-8-lijn gebruikt een Belgische pc code page 850, een tabel van 256 tekens uit de tijd van MS-DOS. Wat daarin staat, komt er gewoon door: de A, maar ook de é en de ╔. De € staat er niet in, want die tabel is ouder dan de euro. .NET kan de € dan niet omzetten en zet er zelf een ? voor in de plaats. Het lettertype komt daar nog niet aan te pas. De emoji wordt ??: het zijn twee chars (het surrogate pair van daarnet), en elk wordt een vraagteken.
Met de lijn gaat alles als UTF-8 naar buiten en komt alles door. In het oude consolevenster wordt de emoji ook dan nog een vierkantje of een �: dat venster kan geen tekens boven 0xFFFF tekenen. Dat ligt aan het venster, niet aan de code.
Werkt de € bij een student ook zonder die lijn? Op een Mac en onder Linux is de console altijd UTF-8, en op Windows kan je UTF-8 als standaard instellen (een beta-optie bij de taalinstellingen). Bij de meeste medestudenten staat dat niet zo, dus de lijn blijft erin.
Nagekeken op een Belgische Windows 11-pc, in Windows Terminal en in het oude consolevenster.
Van code tot scherm
Volg het euroteken. In je code staat "€". In het geheugen zit het nummer 0x20AC (8364), en zolang de tekst binnen C# blijft, kan er niets mislopen: UTF-16 kan elk UNICODE-teken aan.
Pas aan de uitgang wordt het spannend. Console.WriteLine stuurt bytes naar het venster, en Console.OutputEncoding bepaalt welke. In UTF-8 wordt de € drie bytes, E2 82 AC. In code page 850 staat hij niet, dus zet C# er een ? in de plaats. Dat vraagteken ontstaat dus nog voor het lettertype eraan te pas komt.
Het venster leest de bytes en tekent elk teken met zijn lettertype. Geen tekening voor dat teken: een vierkantje. Leest het venster de bytes met een andere tabel dan waarmee ze geschreven zijn: mojibake, zoals €. In de console gebeurt dat zelden, want OutputEncoding stelt het venster mee in. Bij bestanden en mails des te meer, en dat is het verhaal van de volgende slide.
Wat je ziet, vertelt dus waar het misliep: ? is de encoding, een vierkantje is het lettertype, rare tekens zijn een verkeerde tabel.
Mojibake
Ooit een mail gekregen met
Café
in plaats van Café?
En een euroteken wordt zo € .
Ooit een mail gekregen waarin Café als Café stond, of een prijs met € in plaats van een euroteken? Dan heb je mojibake gezien, Japans voor “tekens die van gedaante veranderd zijn”.
Het gebeurt telkens een programma tekst leest met een andere tabel dan waarmee ze geschreven werd. In UTF-8 bestaat de é uit twee bytes: C3 en A9. Een programma dat denkt dat het met een oude tabel van 256 tekens te maken heeft (zoals Windows-1252, de tabel van oudere Windows-programma’s), maakt daar twee tekens van: à en ©. Het euroteken is in UTF-8 zelfs drie bytes, en zo wordt het €.
Denk aan het kluisje: de getallen kloppen, ze worden alleen in de verkeerde kast opgezocht.
UNICODE-kunst
Multiline ASCII-art toon je met een verbatim string @:
string titel = @"
_______ _____
| __ __| __ \
| | | | | |
| | | | | |
| _| | _| __/ ";
Console. WriteLine ( titel);
$ en @ mogen samen: zowel $@"..." als @$"..." werkt en doet hetzelfde.
Raw string literals
Nadeel van @: ook de spaties waarmee je je code inspringt horen bij de string. Sinds C# 11 kan het netter, met drie aanhalingstekens:
string titel = """
_______ _____
| __ __| __ \
| | | | | |
| _| | _| __/
""";
De sluitende """ bepaalt welke inspringing weggeknipt wordt
\ Backslashes en \t blijven letterlijk, net als bij @
$ Een $ ervoor mag ook: $"""..."""
@"..." blijft gewoon werken. Je ziet het nog volop in bestaande code en in wat AI-tools genereren.
Wat vertelt Environment?
Console is maar één bibliotheek. Environment vertelt iets over de machine waarop je programma nú draait:
string gebruiker = Environment. UserName ;
string pcnaam = Environment. MachineName ;
int aantalProcessoren = Environment. ProcessorCount ;
Console. WriteLine ( $"Hallo {gebruiker}, welkom op {pcnaam}." );
Console. WriteLine ( $"Hallo {Environment.UserName}!" );
Hetzelfde programma geeft op elke machine een andere uitvoer. Test zulke code op meer dan één systeem.
Zelf op ontdekking
Typ in Visual Studio Environment. en kijk wat IntelliSense voorstelt: OSVersion, CurrentDirectory, … Niemand kent élke bibliotheek: het is aan jou om te ontdekken welke nuttig zijn voor jouw probleem.
long geheugen = Environment. WorkingSet ;
Console. WriteLine ( $"Dit programma gebruikt {geheugen / 1024 / 1024} MB geheugen" );
WorkingSet is het geheugen dat Windows aan je programma toewees. Dat getal verschilt per pc, en zelfs bij elke run.
Programma afsluiten
Stopt je programma onmiddellijk . Alles wat erna staat, wordt niet meer uitgevoerd.
Het getal is de exitcode :
elk ander getal betekent “er ging iets mis”
Je zag ze al staan in Visual Studio: exited with code 0
Conclusie
Een char is één teken (een 16-bit getal), een string is een reeks chars
UNICODE (UTF-16 in .NET) volgt ASCII op en bevat meer dan een miljoen tekens
\ Escape characters (\n, \t, \") sturen hoe tekst geïnterpreteerd wordt; @ en """ schakelen ze uit
String interpolation ($"...{expressie}...") is de standaardmanier om variabelen in tekst te plaatsen; + vooral om lange tekst over meerdere lijnen te splitsen
Let op de char-val ('A' + 'B' = 131) en op machine-afhankelijke formattering
Environment geeft info over de machine (UserName, MachineName, NewLine) en Exit(0) stopt je programma met een exitcode
Volgende halte: werken met data : converteren, casten en rekenen.
Zie verder
Hoe doen andere programmeertalen hetzelfde? En een korte zoek-de-fout, om zo kritisch mogelijk naar code te leren kijken.
Zie verder: zoek de fout
Deze regel wil tonen waar een bestand bewaard werd, maar de uitvoer ziet er raar uit:
Console. WriteLine ( "Bestand bewaard in C: \t emp \n otities.txt" );
\t is een tab en \n een nieuwe lijn:
Bestand bewaard in C: emp
otities.txt
Zet er een @ voor: @"C:\temp\notities.txt". Of verdubbel elke backslash: "C:\\temp\\notities.txt".
Zie verder: string als char-array
In C bestaat er geen echt string-type. Tekst is daar letterlijk een array van char, afgesloten met een null-karakter \0:
char woord[] = "Tim" ; // {'T', 'i', 'm', '\0'}
printf( " %s\n " , woord);
In C# is string een volwaardig type met handige methodes. Het idee “een string is een reeks chars” zie je in C dus heel letterlijk terug.
Zie verder: het verbatim-idee elders
Python kent net hetzelfde, daar heet het een raw string . Je plaatst een r voor de string in plaats van een @:
met_r = r"C: \ Temp \M yfile . txt"
Backslashes worden gewoon als tekst behandeld, niet als escape character. Handig voor bestandspaden en reguliere expressies.
Zie verder: interpolatie elders
Python (f-string) en JavaScript (template literal) doen exact hetzelfde, met een ander tekentje vooraan:
zin = f"Ik ben { naam} en ik ben { leeftijd} jaar."
const zin = `Ik ben ${ naam} en ik ben ${ leeftijd} jaar.` ;
Het plan
Het startscherm van een spel zoals Dwarf Fortress, en op het einde een voorsmaakje van H6.
Status
naam, levens, goud
Breek het
wat gebeurt er?
Animeren
elke Enter meer goud
Nieuw consoleproject, live gecodeerd met de klas erbij. Reken op twintig à vijfentwintig minuten.
Tot en met stap 5 komt alles uit deze les, H1 of H2: raw strings, UNICODE, kleuren, Write, interpolatie, formatteren en Environment. Stap 6 is een voorsmaakje van while uit H6.
De code per stap staat in de notes van elke slide. Ze is getest met .NET 10, en elke lijn van de kamer is exact 22 hokjes breed.
Stap 1: de muren
Hoe zet je deze kamer met zo weinig mogelijk code op het scherm?
╔════════════════════╗
║ ║
║ ║
║ ║
║ ║
╚════════════════════╝
De muren staan niet op je toetsenbord: kopieer ze van deze slide
Zes lijnen in één keer: een raw string met """
Zoals altijd bovenaan: de UTF-8-lijn
Laat eerst voorstellen doen. Zes keer WriteLine werkt, één string vol \n ook, maar met """ staat de kamer in je code zoals ze op het scherm komt. De tekens kopieer je van de slide, of van symbl.cc (zoek op box drawing ).
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
string kamer = """
╔════════════════════╗
║ ║
║ ║
║ ║
║ ║
╚════════════════════╝
""";
Console. WriteLine ( kamer);
De sluitende """ bepaalt de inspringing: de vier spaties voor elke lijn komen niet op het scherm.
Stap 2: wat staat er in de kamer?
Jullie beslissen. Een paar klassiekers:
☺ een dwerg, zoals in Dwarf Fortress
Tel je hokjes: elke lijn blijft even lang, anders staat de rechtermuur scheef.
Laat de klas roepen wat erin moet en typ het rechtstreeks in de raw string. Een teken erbij betekent een spatie eraf. Wil iemand nu al een emoji, hou die dan voor stap 5.
Een voorbeeld (de deur zit in de ondermuur, zo blijft de bovenmuur vrij voor stap 5):
string kamer = """
╔════════════════════╗
║ $ ║
║ @ ║
║ g ║
║ ~~~~ ║
╚═════════+ ══════════╝
""";
Stap 3: jij in het geel
Hoe maak je enkel de @ geel?
╔════════════════════╗
║ $ ║
║ @ ║
║ g ║
║ ~~~~ ║
╚═════════+══════════╝
Eén string heeft één kleur: knip de kamer in boven, de lijn met de @ en onder
Die ene lijn in drie stukken met Write , en ertussen de kleur wisselen
Op het einde ResetColor()
Vraag eerst hoe ze het zouden doen. Een kleur geldt voor alle tekst die erna komt (H1), dus de lijn met de @ moet uit de string.
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
string boven = """
╔════════════════════╗
║ $ ║
""";
string onder = """
║ g ║
║ ~~~~ ║
╚═════════+ ══════════╝
""";
Console. ForegroundColor = ConsoleColor. DarkGray ;
Console. WriteLine ( boven);
Console. Write ( "║ " );
Console. ForegroundColor = ConsoleColor. Yellow ;
Console. Write ( "@" );
Console. ForegroundColor = ConsoleColor. DarkGray ;
Console. WriteLine ( " ║" );
Console. WriteLine ( onder);
Console. ResetColor ();
Wil de klas ook het goud geel of de goblin rood, dan knip je die lijnen op dezelfde manier. Na twee lijnen voelen ze zelf hoe omslachtig dat wordt.
Stap 4: de statusregel
Onder de kamer: wie speelt er, hoeveel levens, hoeveel goud?
╔════════════════════╗
║ $ ║
║ @ ║
║ g ║
║ ~~~~ ║
╚═════════+══════════╝
tim ♥♥♥ Goud: 0042
De naam van de speler: Environment.UserName
De levens: gewoon ♥♥♥ in de string
Goud altijd met vier cijfers: {goud:D4}
Onder Console.ResetColor(); komt:
string speler = Environment. UserName ;
int goud = 42 ;
Console. WriteLine ( $"{speler} \t ♥♥♥ \t Goud: {goud:D4}" );
Op elke pc staat er een andere naam, zonder dat iemand iets intypt.
Het volledige programma na deze stap:
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
string boven = """
╔════════════════════╗
║ $ ║
""";
string onder = """
║ g ║
║ ~~~~ ║
╚═════════+ ══════════╝
""";
Console. ForegroundColor = ConsoleColor. DarkGray ;
Console. WriteLine ( boven);
Console. Write ( "║ " );
Console. ForegroundColor = ConsoleColor. Yellow ;
Console. Write ( "@" );
Console. ForegroundColor = ConsoleColor. DarkGray ;
Console. WriteLine ( " ║" );
Console. WriteLine ( onder);
Console. ResetColor ();
string speler = Environment. UserName ;
int goud = 42 ;
Console. WriteLine ( $"{speler} \t ♥♥♥ \t Goud: {goud:D4}" );
Stap 5: breek het
Drie keer iets veranderen. Wat gebeurt er?
Zet een draak 🐉 in de plaats van de goblin
De rechtermuur schuift op: een emoji is twee hokjes breed.
Zet de UTF-8-lijn in commentaar
De draak wordt ??. De muren blijven staan: die zitten in code page 850 .
Zet je naam in de bovenmuur, met $"""
Past op jouw pc. Bij een langere gebruikersnaam staat de muur scheef.
1. De draak. Vervang de g door een emoji:
In Windows Terminal neemt een emoji twee hokjes in, dus de muur schuift één plaats op. Haal één spatie na de draak weg en ze staat weer recht. In het oude consolevenster zie je vierkantjes: dat ligt aan het lettertype, niet aan de code.
2. De UTF-8-lijn. Zet de eerste lijn in commentaar:
// Console.OutputEncoding = System.Text.Encoding.UTF8;
Een Belgische pc valt dan terug op code page 850. De draak wordt ??, net als een emoji in het boek. De muren komen er wel door: ╔═╗║╚╝ zitten in die oude tabel. Het hartje niet: dat wordt stuurteken 3, en of je daar iets van ziet, hangt af van het venster. Zet de lijn daarna terug.
3. Je naam in de muur. speler moet nu boven de kamer gedeclareerd worden, en boven krijgt een $:
string speler = Environment. UserName ;
int goud = 42 ;
string boven = $"""
╔═ { speler} ════════════╗
║ $ ║
""";
Zo past het bij een naam van vijf tekens. Pas het aantal ═ aan tot het klopt met jouw gebruikersnaam en zet daarna string speler = "Maximiliaan";: de muur schuift op. Dat is de waarschuwing van Wat vertelt Environment? : hetzelfde programma geeft op elke machine een andere uitvoer.
Stap 6: animeren
Bij elke Enter: scherm leeg, alles opnieuw tekenen, en één goudstuk meer.
╔════════════════════╗
║ $ ║
║ @ ║
║ g ║
║ ~~~~ ║
╚═════════+══════════╝
tim ♥♥♥ Goud: 0042
╔════════════════════╗
║ $ ║
║ @ ║
║ g ║
║ ~~~~ ║
╚═════════+══════════╝
tim ♥♥♥ Goud: 0043
╔════════════════════╗
║ $ ║
║ @ ║
║ g ║
║ ~~~~ ║
╚═════════+══════════╝
tim ♥♥♥ Goud: 0044
Stoppen: Ctrl + C
while (true) herhaalt alles tussen de accolades, voor altijd (meer daarover in H6)
Bovenaan in de lus: Console.Clear()
Onderaan: Console.ReadLine() wacht op Enter, daarna goud++
Waar zet je int goud = 42;?
Boven de lus. Erin begint goud elke ronde opnieuw bij 42.
Een lus zien ze pas in H6. Voor nu volstaat: alles tussen de accolades van while (true) herhaalt zich tot je het programma stopt, met Ctrl+C of door het venster te sluiten.
We vertrekken van het programma van stap 4. Het tekenen en de statusregel gaan in de lus, speler en goud erboven. boven en onder mogen ook buiten de lus blijven: die veranderen niet.
Console. OutputEncoding = System. Text . Encoding . UTF8 ;
string boven = """
╔════════════════════╗
║ $ ║
""";
string onder = """
║ g ║
║ ~~~~ ║
╚═════════+ ══════════╝
""";
string speler = Environment. UserName ;
int goud = 42 ;
while ( true )
{
Console. Clear ();
Console. ForegroundColor = ConsoleColor. DarkGray ;
Console. WriteLine ( boven);
Console. Write ( "║ " );
Console. ForegroundColor = ConsoleColor. Yellow ;
Console. Write ( "@" );
Console. ForegroundColor = ConsoleColor. DarkGray ;
Console. WriteLine ( " ║" );
Console. WriteLine ( onder);
Console. ResetColor ();
Console. WriteLine ( $"{speler} \t ♥♥♥ \t Goud: {goud:D4}" );
Console. ReadLine ();
goud++;
}
Vraag waar int goud = 42; moet staan. Zet je die lijn in de lus, dan krijgt goud elke ronde opnieuw 42 en blijft er 0042 staan, hoe vaak je ook op Enter duwt.
Excel en de genen
In 2020 kregen
27
menselijke genen een nieuwe naam. Door Excel.
SEPT1
de naam van een gen
1 september
Excel maakt er een datum van
In C# kies jij het type: string gen = "SEPT1"; blijft tekst.
Of iets tekst, een getal of een datum is, lijkt een detail. Vraag het maar aan de genetici. Menselijke genen hebben korte namen zoals SEPT1 en MARCH1. Plak je zo’n lijst in Excel, dan beslist Excel zelf dat het datums zijn: SEPT1 wordt 1 september, MARCH1 wordt 1 maart. Zonder waarschuwing, en de oorspronkelijke tekst krijg je niet meer terug.
Een studie uit 2016 vond zulke verminkte genlijsten in ongeveer een vijfde van de wetenschappelijke artikels met Excel-bijlagen. In 2020 gaf de HGNC, de commissie die de namen van menselijke genen beheert, het op en kregen 27 genen een nieuwe naam: SEPT1 heet sindsdien SEPTIN1, MARCH1 werd MARCHF1.