Lezione del 7/4/2014¶
Problema N.3 (lezione precedente)
Leggere un file ascii, separare i vari paragrafi cioè i blocchi di parole in linee consecutive non contenenti linee vuote.
Salvare ogni paragrafo in un vettore e farsi stampare sul terminale il numero di paragrafo il numero di parole che contiene. Compattare (giustificare) ogni paragrafo in modo che riempia al meglio 80 colonne. Salvare su un altro file il file giustificato.
Possibile soluzione (versione semplice)
File 5.3_giustificazione_testo_semplice.rb
1#-------------------------------------------------------------------------#
2# Esercitazioni in Laboratorio per il Corso di #
3# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
4# #
5# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
6# Dipartimento di Ingeneria Industriale, Universita` di Trento #
7# Sito web: http://www.ing.unitn.it/~bertolaz/ #
8# #
9# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
10# #
11# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
12#-------------------------------------------------------------------------#
13
14#__________________________________________________________________________
15# 1. Leggere il file 'testo.txt', salvare ogni paragrafo in una hash
16# e farsi stampare sul terminale ogni riga.
17# Durante questa operazione fare in modo di trascurare le righe
18# corrispondenti all'autore, data, e titolo del documento
19#__________________________________________________________________________
20file = 'testo.txt'
21
22# verifico se il file esiste
23esiste = File.exists? file
24raise ArgumentError, "Il file #{file} non esiste" unless esiste
25
26ht = {:testo => []}
27n_linee_vuote = 0
28IO.foreach(file) do |line|
29 # stampo la linea
30 puts line
31 # pulisco la linea dai terminatori di stringa
32 line.chomp!
33 # salvo il testo in un array
34 ht[:testo] << line if n_linee_vuote >= 2
35 # conto il numero delle linee vuote
36 n_linee_vuote += 1 if line.empty?
37end
38
39
40
41
42#__________________________________________________________________________
43# 2. Contare e farsi stampare il numero di paragrafi, parole e di caratteri
44# (inclusi spazi bianchi) nel file.
45#__________________________________________________________________________
46ht[:n_paragrafi] = ht[:testo].size
47ht[:n_parole] = 0
48ht[:n_caratteri] = 0
49ht[:testo].each do |paragrafo|
50 # numero di caratteri
51 ht[:n_caratteri] += paragrafo.size
52 ht[:n_parole] += paragrafo.split(" ").size
53end
54
55puts "_"*40
56puts "Il testo contiene:\n\t#{ht[:n_paragrafi]} paragrafi\n\t#{ht[:n_parole]} parole\n\t#{ht[:n_caratteri]} caratteri"
57puts "_"*40
58
59
60
61
62#__________________________________________________________________________
63# 3. Giustificare il testo con una larghezza della pagina pari a
64#__________________________________________________________________________
65ht[:larghezza_testo] = 100 # numero di caratteri in una linea
66
67# quando non posso aggiungere caratteri per completare la mia linea,
68# aggiungo spazi bianchi dopo ogni parola a partire da sinistra.
69def riempi_stringa(str, lunghezza)
70 raise ArgumentError, "Il primo argomento deve essere una stringa" unless str.is_a? String
71 raise ArgumentError, "Il secondo argomento deve essere un intero" unless lunghezza.is_a? Integer
72
73 l = str.size
74 nsb = lunghezza-l # numero di spazi bianchi da aggiungere
75
76
77 return str if nsb == 0
78
79 par = str.chomp.split " "
80
81 i = 1
82 while nsb > 0
83 # post poni uno spazio bianco alla fine di ogni parola
84 par[i].insert(0, " ")
85 i += 1
86 nsb -= 1
87 end
88
89 nuova_linea = par.join " "
90 l = nuova_linea.size
91
92 # se le parole nella linea sono meno degli spazi bianchi,
93 # aggiungo spazi bianchi dopo l'ultima parola
94 nsb = lunghezza-l # numero di spazi bianchi da aggiungere
95 nuova_linea << " "*nsb
96
97 l = nuova_linea.size
98 begin
99 msg = "La lunghezza della linea #{nuova_linea.inspect} di #{l} non e` compatibile con #{lunghezza}"
100 raise RuntimeError, msg unless l == lunghezza
101 rescue
102 binding.pry
103 end
104 nuova_linea << "\n" # la linea deve andare accapo
105 return nuova_linea
106end # def
107
108
109# Separo ogni parola in ogni paragrafo nel testo
110testo_separato = []
111ht[:testo].each{|par| testo_separato << par.split(" ") }
112
113# Giustifico il testo. Ogni array (i.e. paragrafo) contiene le stringhe
114# giustificate (i.e. linee) separate da terminatori di stringa
115ht[:testo_giustificato] = []
116ht[:testo].each do |paragrafo|
117 parole = paragrafo.split " "
118
119 paragrafo_giustificato = ""
120
121 linea = ""
122
123 # fin tanto che non ho giustificato tutte le parole...
124 while parole.size > 0
125 # togli la parola dall'array 'parole' e mettila in 'p'
126 p = parole.shift
127
128 # devo aggiungere la parola alla linea solo se a valle di questa operazione
129 # la conta dei caratteri non eccede ht[:larghezza_testo]
130 linea_giustificata = linea + " " + p
131
132 l = linea_giustificata.size
133
134 if l < ht[:larghezza_testo]
135 linea = linea_giustificata
136
137 # se la linea e` abbastanza corta e ho finito le parole nel paragrafo,
138 # allora appendi la linea al paragrafo cosi` com'e`
139 if parole.size == 0
140 paragrafo_giustificato << linea << "\n"
141 # reinizializza la linea
142 linea = ""
143 end
144
145 else
146 linea = riempi_stringa(linea, ht[:larghezza_testo])
147
148 # aggiungo la linea al paragrafo
149 paragrafo_giustificato << linea
150
151 # reinizializza la linea con la parola che avanza dalla linea precedente
152 linea = p
153
154 # se 'p' e` l'ultima parola del paragrafo, mandala accapo
155 paragrafo_giustificato << p << "\n" if parole.empty?
156
157 end # if
158 end # while parole
159
160 paragrafo_giustificato << "\n"
161 ht[:testo_giustificato] << paragrafo_giustificato
162end # .each
163
164puts "="*40
165ht[:testo_giustificato].each{|par| puts par}
166
167
168#__________________________________________________________________________
169# 3. Salvare il testo giustificato in un nuovo file
170#__________________________________________________________________________
171
172File.open("testo_giustificato.txt", 'w') do |file|
173 ht[:testo_giustificato].each{|par| file.puts par}
174end
Possibile soluzione (versione completa)
File 5.4_giustificazione_testo_completo.rb
1#-------------------------------------------------------------------------#
2# Esercitazioni in Laboratorio per il Corso di #
3# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
4# #
5# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
6# Dipartimento di Ingeneria Industriale, Universita` di Trento #
7# Sito web: http://www.ing.unitn.it/~bertolaz/ #
8# #
9# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
10# #
11# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
12#-------------------------------------------------------------------------#
13
14#__________________________________________________________________________
15# 1. Leggere il file 'testo.txt', salvare ogni paragrafo in una hash
16# e farsi stampare sul terminale ogni riga.
17# Durante questa operazione fare in modo di trascurare le righe
18# corrispondenti all'autore, data, e titolo del documento
19#__________________________________________________________________________
20file = 'testo.txt'
21
22# verifico se il file esiste
23esiste = File.exists? file
24raise ArgumentError, "Il file #{file} non esiste" unless esiste
25
26ht = {:testo => []}
27n_linee_vuote = 0
28IO.foreach(file) do |line|
29 # stampo la linea
30 puts line
31 # pulisco la linea dai terminatori di stringa
32 line.chomp!
33 # salvo il testo in un array
34 ht[:testo] << line if n_linee_vuote >= 2
35 # conto il numero delle linee vuote
36 n_linee_vuote += 1 if line.empty?
37end
38
39
40
41
42#__________________________________________________________________________
43# 2. Contare e farsi stampare il numero di paragrafi, parole e di caratteri
44# (inclusi spazi bianchi) nel file.
45#__________________________________________________________________________
46ht[:n_paragrafi] = ht[:testo].size
47ht[:n_parole] = 0
48ht[:n_caratteri] = 0
49ht[:testo].each do |paragrafo|
50 # numero di caratteri
51 ht[:n_caratteri] += paragrafo.size
52 ht[:n_parole] += paragrafo.split(" ").size
53end
54
55puts "_"*40
56puts "Il testo contiene:\n\t#{ht[:n_paragrafi]} paragrafi\n\t#{ht[:n_parole]} parole\n\t#{ht[:n_caratteri]} caratteri"
57puts "_"*40
58
59
60
61
62#__________________________________________________________________________
63# 3. Giustificare il testo con una larghezza della pagina pari a
64#__________________________________________________________________________
65ht[:larghezza_testo] = 100 # numero di caratteri in una linea
66
67# quando non posso aggiungere caratteri per completare la mia linea,
68# aggiungo spazi bianchi in corrispondenza delle parole piu` lunghe
69def riempi_stringa(str, lunghezza)
70 raise ArgumentError, "Il primo argomento deve essere una stringa" unless str.is_a? String
71 raise ArgumentError, "Il secondo argomento deve essere un intero" unless lunghezza.is_a? Integer
72
73 l = str.size
74 nsb = lunghezza-l # numero di spazi bianchi da aggiungere
75
76
77 return str if nsb == 0
78
79 par = str.chomp.split " "
80 # ordino le parole dalla piu` lunga alla piu` corta
81 par_ord = par.sort{|x,y| y.size <=> x.size}
82
83 while nsb > 0
84 # trova la posizione della parola piu` lunga nella frase
85 i = par.index par_ord.shift
86
87 # non aggiungere spazi bianchi prima della prima parola nella linea
88 next if i == 0
89
90 # preponi uno spazio bianco alla parola piu` lunga
91 par[i].insert(0, " ")
92
93 nsb -= 1
94 end
95
96 nuova_linea = par.join " "
97 l = nuova_linea.size
98
99 # se le parole nella linea sono meno degli spazi bianchi,
100 # aggiungo spazi bianchi dopo l'ultima parola
101 nsb = lunghezza-l # numero di spazi bianchi da aggiungere
102 nuova_linea << " "*nsb
103
104 l = nuova_linea.size
105 begin
106 msg = "La lunghezza della linea #{nuova_linea.inspect} di #{l} non e` compatibile con #{lunghezza}"
107 raise RuntimeError, msg unless l == lunghezza
108 rescue
109 binding.pry
110 end
111 nuova_linea << "\n" # la linea deve andare accapo
112 return nuova_linea
113end # def
114
115
116# Separo ogni parola in ogni paragrafo nel testo
117testo_separato = []
118ht[:testo].each{|par| testo_separato << par.split(" ") }
119
120# Giustifico il testo. Ogni array (i.e. paragrafo) contiene
121# le stringhe giustificate (i.e. linee) separate da terminatori di stringa
122ht[:testo_giustificato] = []
123ht[:testo].each do |paragrafo|
124 parole = paragrafo.split " "
125
126 paragrafo_giustificato = ""
127
128 linea = ""
129
130 # fin tanto che non ho giustificato tutte le parole...
131 while parole.size > 0
132 # togli la parola dall'array 'parole' e mettila in 'p'
133 p = parole.shift
134
135 # devo aggiungere la parola alla linea solo se a valle di questa
136 # operazione la conta dei caratteri non eccede ht[:larghezza_testo]
137 linea_giustificata = linea + " " + p
138
139 l = linea_giustificata.size
140
141 if l < ht[:larghezza_testo]
142 linea = linea_giustificata
143
144 # se la linea e` abbastanza corta e ho finito le parole nel paragrafo,
145 # allora appendi la linea al paragrafo cosi` com'e`
146 if parole.size == 0
147 paragrafo_giustificato << linea << "\n"
148 # reinizializza la linea
149 linea = ""
150 end
151
152 else
153 linea = riempi_stringa(linea, ht[:larghezza_testo])
154
155 # aggiungo la linea al paragrafo
156 paragrafo_giustificato << linea
157
158 # reinizializza la linea con la parola che avanza dalla linea precedente
159 linea = p
160
161 # se 'p' e` l'ultima parola del paragrafo, mandala accapo
162 paragrafo_giustificato << p << "\n" if parole.empty?
163
164 end # if
165 end # while parole
166
167 paragrafo_giustificato << "\n"
168 ht[:testo_giustificato] << paragrafo_giustificato
169end # .each
170
171puts "="*40
172ht[:testo_giustificato].each{|par| puts par}
173
174
175#__________________________________________________________________________
176# 3. Salvare il testo giustificato in un nuovo file
177#__________________________________________________________________________
178
179File.open("testo_giustificato.txt", 'w') do |file|
180 ht[:testo_giustificato].each{|par| file.puts par}
181end
File testo