Eräät ohjelmointikielet, kuten Fortranin vanhimmat versiot, ovat vahvasti rivirakenteisia siinä mielessä, että lähdekielisen ohjelman (source program) pitää jakautua riveille määrätyllä tavalla. Muissakin kielissä on yleisesti sääntöjä, jotka rajoittavat ohjelman vapaata jakamista eri riveille. Esimerkiksi C-kielessä on ns. direktiivit kirjoitettava kukin omalle rivilleen.
Erittäin tavallista on, että merkkijonovakiota
ei saa ainakaan suoraan jakaa eri riveille. Koska toisaalta
usein tarvitaan pitkiä merkkijonovakioita, on yleensä käytössä
jokin jatkorivikonventio. Tyypillinen konventio on sellainen,
että rivin loppuun kirjoitetaan
kenoviiva \
ja kirjoittamista jatketaan
heti seuraavan rivin alusta (vaikka muuten olisi käytetty sisennyksiä).
Esimerkki C-kielestä:
char *s = "Tämä\ on merkkijono"merkitsee samaa kuin
char *s = "Tämäon merkkijono"
Huomannet sudenkuopan: on helppoa luulla, että rivinvaihto
vastaisi välilyöntiä, kuten se usein vastaa.
Esimerkiksi Fortranin uusissa versioissa (Fortran-90:stä alkaen) ns.
vapaassa muodossa (free source form) on suunnilleen
vastaava jatkorivikonventio mutta merkkinä on \
:n
asemesta et-merkki &
; tosin asiaan vielä
liittyy eräitä lisäsääntöjä.
Rivinvaihtojen sisällyttäminen merkkijonovakioon
saattaa myös olla mahdollista. Tämä on tarkoin erotettava edellä kuvatusta
jatkorivikäytännöstä. C-kielessä, ja sitä matkien useissa muissa kielissä,
voidaan tarkoitukseen käyttää merkintää \n
. Esimerkiksi
"hui\nhai"
on merkkijonovakio, jonka sisällä on rivinvaihto.
C-standardin mukaan \n
on kontrollikoodi, jonka merkitys on
"moves the active position to the initial position of the next line".
(Tästä seuraa, että sen fyysinen toteutus riippuu siitä järjestelmästä,
jossa C-ohjelma suoritetaan. Kuitenkin sen tulee olla yksi
koodi, yksi "ohjausmerkki",
esim. LF tai CR mutta ei niiden yhdistelmä, koska \n
vie (esim. merkkijonovakion sisäisessä esityksessä) saman verran tilaa
kuin yksi merkki. Tästä seuraa, että jos järjestelmässä on käytössä
CR LF rivinvaihdon esityksenä, täytyy C-kielen toteutuksen automaattisesti
muuntaa \n
:n sisäinen esitys tulostuksessa CR LF:ksi.)
Aivan eri asia sitten on, miten ohjelma lukee tekstidataa ja kirjoittaa sitä. Kuten kohdassa Rivi ja tietue mainittiin, aluksi käsittely oli yleensä rivipohjaista - ja on usein nykyisinkin. Vaikka esimerkiksi Perliä pidetään modernina kielenä, se on suunniteltu ensisijaisesti rivi kerrallaan tapahtuvaan datan käsittelyyn. Perlin yksinkertaisimman käytön perusidiomeihin kuuluu rakenne
while(<>) { käsittele syöterivi print; }
missä käsittely voi koostua esimerkiksi käskystä
s/x/ks/g;
(korvaa jokainen x-kirjain kirjainparilla ks).
Tässä ei missään vaiheessa erikseen sanota, mikä data on käsittelyn
kohteena, vaan se on koko ajan implisiittisesti "nykyinen syöterivi".
(Tosin siihen voitaisiin viitata muuttujalla $_
.)
Useat ohjelmointikielet on suunniteltu niin, ettei tekstidataa edes voi lukea ja tulostaa kuin rivi kerrallaan. Toki yksittäisiä merkkejäkin voi käsitellä, mutta siten, että esim. syötteen käsittelyssä ohjelma ensin lukee rivin vaikkapa taulukkoon, josta se sitten indeksoimalla poimii merkkejä. Tämä toimi ja toimii hyvin monissa tilanteissa, mutta vuorovaikutteisista ohjelmista tulee kömpelöitä, jos jokainen näppäimistöltä annettava ohjaus on päätettävä return- tai enter-näppäintä painamalla. Muutoinkin vuorovaikutteinen, merkki kerrallaan tapahtuva syöttö ja tulostus vaativat usein erikoistoimia, esimerkiksi erityisesti siihen sopivien aliohjelmien käyttöä.
Erikseen mainittakoon
Fortran-ohjelmoinnin se vaikeus, että
jokainen write
- tai print
-lause tulostaa
vähintään yhden rivin. Aiemmin tämä ongelma kierrettiin järjestämällä
tulostustoiminnot niin, että ohjelma tulostaa vain tilanteissa, joissa
sillä on koko rivi "valmiina".
Tämä ei tietenkään ollut mahdollista esim. tilanteessa, jossa halutaan
tulostaa tekstiä kehotteeksi niin, että käyttäjä voi kirjoittaa
syöttötiedot suoraan sen perään, samalle riville.
Saatettiin myös käyttää erilaisia kielen
epästandardeja laajennuksia. Fortran-90:ssä ongelma ratkeaa siististi
käyttämällä tulostuslauseessa argumenttia
advance='no'
.
Toisaalta silloinkin, kun kielen syöttö- ja tulostustoiminnot on
suunniteltu ensisijassa merkeittäiseen käsittelyyn, kannattaa
usein käyttää rivipohjaista käsittelyä apuna. Esimerkiksi C-kielisen
ohjelmoinnin tyylioppaat usein suosittavat tekemään ohjelmat niin, että
ohjelma ensin lukee rivin merkkejä puskuriin (merkkitaulukkoon) ja
sitten siitä sitten esimerkiksi sscanf
-funktiolla (eikä
suoraan syötetiedoista scanf
-funktiolla). Jos esimerkiksi
on olennaista tunnistaa, miten numeerinen
syöttötietoaineisto jakautuu eri riveille,
niin scanf
-funktiota ei voi käyttää, koska se iloisesti ohittaa
rivinvaihdot pitäen niitä välilyönteihin rinnastuvina.
Yleensä ns. korkean tason ohjelmointikielet on pyritty suunnittelemaan
niin, että ohjelmat voidaan kirjoittaa
riippumattomiksi rivinvaihtojen esityksestä.
Ohjelman voi siis koodata lukemaan rivi kerrallaan tai tunnistamaan
rivinvaihtoja ilman, että ohjelmoijan tarvitsee edes tietää, onko
rivinvaihdon esitysmuoto CR, LF, CR LF vai kenties jotain muuta.
Esimerkiksi kun C-ohjelma lukee tiedostosta dataa merkki kerrallaan, se
"näkee" rivinvaihdon C-standardin mukaisella tavalla kontrollikoodina,
johon voidaan viitata merkinnällä \n
(esim. if(merkki=='\n')
...). Näin siitä riippumatta, mikä
rivinvaihtojen fyysinen esitysmuoto tiedostoformaatissa on.
Eri asia sitten on, että lukemalla tiedostoa binaarisesti
(esim. fread
-funktiolla) on mahdollista päästä näkemään
se fyysinen esitysmuotokin.
Selvää on, että ohjelmoijan kannattaa tulostuksessa
vastaavasti yleensä käyttää kielen rakenteita, jotka on määritelty
niin, että ne saavat aikaan rivinvaihdon, esim. Pascalissa writeln
ja C:ssä vaikkapa putchar('\n')
, yhden monista
mahdollisuuksista mainitaksemme. Sen sijaan
putchar('\012')
012
on
sen luvun oktaaliesitys, jonka desimaaliesitys on 10). Vaikka vaikutus
on useissa järjestelmissä sama, niin se ei suinkaan ole
yleisesti sama.
Yleensä tulostuksen loppuunkin on syytä kirjoittaa
rivinvaihto eli kirjoittaa viimeinen rivi kuten muutkin,
esim. C:ssä printf("Loppu.\n")
, ei
printf("Loppu.")
.
Perusteluja tälle on
seuraavassa kohdassa.