OPERAZIONI CON STRINGHE
Le operazioni più interessanti da fare, per ora, con le stringhe sono:
determinare la lunghezza della stringa, cioè quanti caratteri contiene,
concatenare insieme più stringhe.
length
La funzione length(Stringa) restituisce la lunghezza della stringa.
Esempio
Supponiamo di avere uno spazio di 80 caratteri e vogliamo centrare
in questo spazio la scritta ‘SONO AL CENTRO’
StringaDaMostrare:= ‘SONO AL CENTRO’;
Spazi:=(80-length(StringaDaMostrare)) DIV 2;
writeln(‘ ‘:Spazi, StringaDaMostrare);
|………………………SONO AL CENTRO………………………|
CONCATENAZIONE
+
concat
Esempio
‘Teresa’
‘e’
‘Giacomo’
‘Teresa’ + ‘ e ’ + ‘Giacomo’
Teresa e Giacomo
La stringa può essere vista come un ARRAY.
TYPE Stringa=STRING[Lunghezza]
UnaStringa:Stringa
Allora SONO QUI si presenta così
S
O
N
O
1
2
3
4
UnaStringa[3] = N
UnaStringa[7] = U
5
Q
U
I
6
7
8
ESEMPIO
Trasformare una stringa qualunque in una stringa tutta maiuscolo.
PROCEDURE MinMaius(VAR UnaStringa: Stringa);
{trasforma una stringa tutta in maiuscolo }
VAR
Posizione: integer; {posizione del carattere nella stringa}
BEGIN
FOR Posizione:=1 TO length(UnaStringa) DO
UnaStringa[Posizione]:=Maiuscolo(UnaStringa[Posizione])
END;
FUNCTION Maiuscolo(Carattere:char):char;
BEGIN
IF Carattere IN [‘a’..’z’] THEN
Maiuscolo:=chr(ord(Carattere) + ord(’A’) - ord(‘a’))
ELSE
Maiuscolo:=Carattere
END;
Algoritmo per leggere stringhe e numeri da un file testo
Problema:
Dato un file testo in cui ci sono una stringa di caratteri e numeri
si vuole separare la stringa dai numeri e fare delle operazioni su
questi ultimi.
In fase di scrittura del file non imponiamo una lunghezza fissa alle
stringhe in lettura ma conveniamo di indicare la fine della stringa con
un carattere sentinella ad esempio ‘^’.
Imponiamo invece la lunghezza massima del rigo.
Esempio
Verdi Carlo^
30
Esposito Franco^
Verdi Carlo^
30
Esposito Franco^
1
29
25
29
25
28
27
28
27
30
29
30
29
30
30
40
Pseudocodice
{leggi i caratteri finchè non incontri la sentinella e concatenali in
una stringa}
•Sentinella  ‘^’ {Inizializza il carattere sentinella}
•UnaStringa  ‘’ {Inizializza la stringa con la stringa nulla ‘’}
•read(InFile,Carattere)
•WHILE Carattere <> Sentinella DO
•UnaStringa  UnaStringa + Carattere
•read(InFile,Carattere)
In generale bisogna controllare:
• se il carattere è la sentinella
• se il numero di caratteri letti e accumulati nella stringa sono <= della
lunghezza massima permessa alla stringa
• se siamo a fine rigo, cioè se il prossimo carattere è eoln
Pseudocodice
WHILE Carattere <> Sentinella DO
BEGIN
IF NOT eoln(UnFile) AND NOT (lenght(Stringa)=MaxLung) THEN
read(UnFile,Carattere)
UnaStringa  UnaStringa + Carattere
ELSE
Carattere  Sentinella
END;
PROCEDURE LeggiUnRigo(Sentinella: char; VAR UnaStringa:
StringaNome; VAR InFile:text);
VAR
Carattere: char;
BEGIN
UnaStringa:='';
{inizializza con stringa nulla}
IF NOT eoln(InFile) THEN
BEGIN
read(InFile,Carattere)
END
ELSE
Carattere:=Sentinella;
WHILE (Carattere<>Sentinella) DO
BEGIN
UnaStringa:=UnaStringa+Carattere;
IF NOT eoln(InFile) AND (length(UnaStringa)<>
LunMassima) THEN
BEGIN
read(InFile,Carattere)
END
ELSE
Carattere:=Sentinella
END
END;
ESEMPIO 9.2
Problema:
Si hanno i dati relativi a M esami fatti da N studenti.
Vogliamo leggere questi dati e per ogni studente fare la media.
Il file di dati si presente così:
5
4
Rossi Carlo^
30 28 18 25
Rossi Lucio^
18 25 22 21
Bianchi Ugo^
18 18 18 18
Verdi Carlo^
30 29 28 30
Esposito Franco^
25 27 29
30
Al primo rigo sono segnati il numero N degli studenti e il numero M
di esami.
Nei righi successivi ci sono i dati. Ogni stringa che identifica lo studente
è terminata con il carattere ‘^’.
Output atteso
Rossi Carlo ha una
Rossi Lucio ha una
Bianchi Ugo ha una
Verdi Carlo ha una
Esposito Franco ha
media di 24.5 su 4 test.
media di 28.25 su 4 test.
media di 22.3 su 4 test.
media di 21.5 su 4 test.
una media di 26.2 su 4 test.
PROGRAM EsamiTest(output,Risultati);
CONST
Sentinella='^';
LunMassima=40;
TYPE
StringaNome=STRING[LunMassima];
VAR
Risultati: text;
NumeroStudenti,TotaleStudenti,TotaleTest: integer;
PROCEDURE Inizializza(VAR Risultati: text;
VAR TotaleStudenti,TotaleTest: integer);
BEGIN ………….. END;
PROCEDURE LeggiRigo(Sentinella: char; VAR Nome:StringaNome; VAR
Risultati:text);
BEGIN ……………………….END;
PROCEDURE MostraStudente(TotaleTest:integer;VAR Risultati:text);
BEGIN ……………………………… END;
{************************** }
BEGIN
Inizializza(Risultati,TotaleStudenti,TotaleTest);
FOR NumeroStudenti:=1 TO TotaleStudenti DO
BEGIN
MostraStudente(TotaleTest,Risultati)
END;
readln
END.
PROCEDURE Inizializza(VAR Risultati: text;
VAR TotaleStudenti,TotaleTest: integer);
BEGIN
assign(Risultati,'C:\TP\ESEMPI\STUDENT1.TXT');
reset(Risultati);
readln(Risultati,TotaleStudenti,TotaleTest)
END;
PROCEDURE LeggiRigo(Sentinella: char; VAR Nome:StringaNome; VAR
Risultati:text);
VAR
Carattere: char;
BEGIN
Nome:='';
{inizializza con stringa nulla}
read(Risultati,Carattere);
WHILE (Carattere<>Sentinella) DO
BEGIN
Nome:=Nome+Carattere;
read(Risultati,Carattere);
END
END;
PROCEDURE MostraStudente(TotaleTest:integer;VAR Risultati:text);
VAR
Somma,ContoTest,Punteggio: integer;
Nome: StringaNome;
BEGIN
LeggiRigo(Sentinella,Nome,Risultati);
Somma:=0;
FOR ContoTest:=1 TO TotaleTest DO
BEGIN
read(Risultati,Punteggio);
Somma:=Somma+Punteggio
END;
readln(Risultati);
{non ci sono altri risultati sul rigo}
write(Nome, ' ha una media di ');
writeln(Somma/TotaleTest:4:2, ' su ',TotaleTest:1,' test')
END;
ESEMPIO 9.3
Supponiamo di dover introdurre delle scritte di controllo in un programma che non
funziona. Dopo aver trovato l’errore vogliamo eliminare le scritte di controllo rapidamente.
Mettiamo davanti ad ogni scritta di controllo una sentinella uguale per tutte le scritte.
{D}
{D}
{D}
writeln(Variabile1,’Testo’,…);
WHILE ….. DO
………………….
writeln(Variabile1,’Testo’,…);
FOR ….. TO
………………….
writeln(Variabile1,’Testo’,…);
Problema:
Scrivere un programma tale che permette
di eliminare da un file indicato
dall’utente tutti i righi preceduti dalla
stringa {D} riscrivendo su un nuovo file
solo i righi non preceduti da {D}.
Pseudo-codice
ApriFile(InFile,OutFile),
WHILE NOT eof(InFile) DO
CreaRigo(InFile,OutFile)
close(InFile)
ApriFile: apre i file
close(OutFile)
CreaRigo :decide se copiare o meno il rigo
letto a seconda che sia o meno preceduto da
{D}
PROGRAM Diagnostico(input, output, InFile, OutFile);
{elimina dal file InFile tutti i righi preceduti da {D} e lo riscrive
cosi’ corretto in OutFile
}
CONST Sentinella='{D}'; LunMass=80;
TYPE
TipoStringa=STRING[LunMass];
VAR InFile, OutFile: text;
{ --------------------------- }
PROCEDURE LeggiNomeFile(VAR NomeFile:TipoStringa;VAR UnFile:text);
BEGIN …………………….. END;
PROCEDURE ApriFile(VAR InFile,OutFile:text);
BEGIN …………………. END;
PROCEDURE PrendiRigo(Spazio: char; VAR StringaRisultante: TipoStringa;
VAR Infile:text);
BEGIN …………………………. END;
PROCEDURE CreaRigo(VAR InFile,OutFile: text);
BEGIN ………………………………………………. END;
{ ********* BODY ********* }
BEGIN
ApriFile(InFile,OutFile);
writeln(' Sto copiando il file .........');
WHILE NOT eof(InFile) DO
CreaRigo(InFile,OutFile);
close(InFile);
close(OutFile);
writeln(' FINE LAVORO');
readln
END.
PROCEDURE LeggiNomeFile(VAR NomeFile:TipoStringa;VAR UnFile:text);
{ legge i nomi dei file }
BEGIN
writeln;
readln(NomeFile);
assign(UnFile,NomeFile)
END;
PROCEDURE ApriFile(VAR InFile,OutFile:text);
{ apre i file }
VAR
NomeFile: TipoStringa;
BEGIN
write('Elimina i righi preceduti da {D}, dal file: ');
LeggiNomeFile(NomeFile,InFile);
write('Dammi il nome che vuoi attribuire al file corretto: ');
LeggiNomeFile(NomeFile,OutFile);
reset(InFile);
rewrite(OutFile)
END;
PROCEDURE PrendiRigo(Spazio: char; VAR StringaRisultante: TipoStringa;
VAR Infile:text);
{ prende la prima stringa presente sul rigo - si suppone che la
sentinella {D} si trovi a inizio rigo}
VAR
Carattere:char;
BEGIN
StringaRisultante:='';
IF NOT eoln(InFile) THEN
Read(InFile,Carattere)
ELSE
Carattere:=Spazio;
WHILE Carattere<>Spazio DO
BEGIN
StringaRisultante:= StringaRisultante+Carattere;
IF NOT eoln(InFile) THEN
Read(InFile,Carattere)
ELSE
Carattere:=Spazio
END
END;
PROCEDURE CreaRigo(VAR InFile,OutFile: text);
{copia tutti i righi da InFile a OutFile purchè senza sentinrlla}
VAR
Primo, Resto: TipoStringa;
BEGIN
PrendiRigo(' ',Primo,InFile);
readln(InFile,Resto);
IF Primo<>Sentinella THEN
writeln(OutFile,Primo+' '+Resto);
END;
{ ******** BODY ******** }
BEGIN
ApriFile(InFile,OutFile);
writeln(' Sto copiando il file .........');
WHILE NOT eof(InFile) DO
CreaRigo(InFile,OutFile);
close(InFile);
close(OutFile);
writeln(' FINE LAVORO');
readln
END.
AVVERTENZE E SUGGERIMENTI
• usare sempre dei Nomi di Variabile per accedere al contenuto dei file,
mai direttamente il nome reale
• usare sempre close dopo avere utilizzato dei file in letture o scrittura. In
scrittura è obbligatorio pena la perdita di dati o danni maggiori.
• nei vari dialetti l’apertura e la chiusura può essere diversa
• quando si legge un file assicurarsi sempre di controllare l’eof
altrimenti il programma va in errore
• non usare mai REPEAT ………… UNTIL per controllare eof o eoln.
REPEAT
WHILE NOT eoln DO
elabora
UNTIL
SI
eof ?
NO
eof ?
NO
SI
elabora
REPEAT
REPEAT
read(UnFile, Qualcosa)
elabora(Qualcosa)
UNTIL eoln(UnFile)
VA IN CRASH SE IL FILE E’ VUOTO
readln(UnFile)
UNTIL eof(UnFIle)
s
read
s
p
a
eoln
a
eoln
p
s
WHILE NOT eoln DO
elabora
read(Carattere)
END
readln:
L’ultimo carattere non viene elaborato
perché si esce prima dal loop.
p
a
p
s
p
a
a
eoln
eoln
WHILE NOT eoln DO
read
elabora
s
p
a
eoln
s
p
a
eoln
a
eoln
p
s
s
p
a
eoln
Supponiamo di avere un ciclo per elaborare o una linea di dati oppure che esca sulla base di un
carattere sentinella.
read(unFile, UnValore)
WHILE NOT eoln(UnFile) AND NOT (UnValore è una sentinella) DO
elabora
read(unFile, UnValore)
Funziona bene se esce per la presenza della sentinella
Funziona male se esce per la presenza del eoln
Supponiamo di avere sempre un ciclo per elaborare o una linea di dati oppure che esca sulla
base di un carattere sentinella.
WHILE NOT eoln(UnFile) AND NOT (UnValore è una sentinella) DO
read(unFile, UnValore)
elabora
Funziona male se esce per la presenza della sentinella
Funziona bene se esce per la presenza del eoln
CODICE CORRETTO
IF NOT eoln(UnFile) THEN
read(unFile, UnValore)
ELSE
UnValore  sentinella
WHILE NOT (UnValore è una sentinella) DO
elabora
IF NOT eoln(UnFile) THEN
read(unFile, UnValore)
ELSE
UnValore  sentinella
Quando in un file ci sono numeri che devono essere letti, fare
attenzione che gli eoln siano messi accanto alla fine del numero
e non preceduti da uno spazio.
SBAGLIATO!!!
Esempio:
44 55 69 <eoln>
33 68 98 45 87<eoln)
WHILE NOT eoln(InFile) DO
BEGIN
read(InFile, Numero);
elabora(Numero)
END;
readln(InFile)
In questo caso non vengono letti due righi di 3 e 5 numeri ma un
solo rigo di 8 numeri, perché dopo avere letto 69 poiché c’è uno spazio
non legge <eoln> ma va a leggere direttamente il numero successivo
Scarica

BEGIN ………….. END