Table of Contents

Tema 2 - Formatare text

Responsabili

Informații

Update 10 Decembrie 8:55 - Deadline soft extins cu o zi.

Obiective

Introducere

Pe Maria a șocat-o vestea că documentația pentru programele scrise în facultate se face în plain text, pentru că e obișnuită să lucreze în Microsoft Word și să formateze textul cât mai frumos. Ea vrea să găsească cât mai multe moduri prin care să înfrumusețeze un fișier simplu .txt, așa că folosește ASCII Art și vrea să creeze un program care să formateze textul pentru ea.

Cerință

Maria vrea ca programul ei să primească trei argumente în linia de comandă. Primul argument reprezintă un șir de caractere care indică operațiile pe care dorește să le aplice textului dintr-un fișier (separate prin virgulă), al doilea argument este calea către fișierul respectiv, iar al treilea argument este numele fișierului formatat care va fi generat.

Puteți porni de la scheletul de cod de aici, care face citirea și scrierea în/din fișier pentru voi. Fișierul Makefile inclus conține regulile build, clean și run. Pentru a da argumente regulii run, formatul este conform exemplului următor:

make run ARGS='"W 50, C 0 0, L1" in.txt out.txt'

Exemplu de rulare:

./format_text "W 50, C 0 0, L 1" in.txt out.txt

În exemplul de mai sus se efectuează următoarele operații:

  • se citesc datele din fișierul in.txt
  • textul este formatat astfel încât o linie să nu depășească 50 de caractere (Wrap)
  • prima linie este centrată (Center)
  • toate liniile începând cu linia 1 sunt aliniate la stânga (align Left)
  • textul astfel obținut este scris în fișierul out.txt

Maria știe că fișierele pe care le va formata nu vor avea niciodată mai mult de 1.000 de linii sau mai mult de 1.000 de caractere pe o singură linie.

În șirul de caractere care indică operațiile (îl vom numi “comandă”), pot exista oricâte spații între operații și parametri. Acestea nu influențează operațiile. În plus, primul caracter din operație (care diferă în funcție de tipul operației) poate fi atât lowercase, cât și uppercase, având aceeași semnificație. O comandă nu ar trebui să aibă mai mult de 10 operații, iar o operație validă nu are mai mult de 20 de caractere (cu tot cu spații).

În notația formatului operațiilor următoare, parametrii opționali sunt înconjurați de paranteze pătrate, similar cu formatul operațiilor descrise în manpage.

Operațiile care au ca parametri [start_line [end_line]] se aplică pe liniile din intervalul [start_line, end_line], sau de la start_line până la sfârșitul fișierului dacă end_line nu este precizat. Dacă nici unul dintre cei doi parametri nu este precizat, operația se va efectua pe întregul fișier.

Wrap text

W max_line_length

Operația wrap adaugă și elimină caractere newline din text astfel încât textul să se încadreze în max_line_length (să aibă lungimea - în octeți - mai mică sau egală), fără a permite linii prea scurte (în afara ultimei linii dintr-un paragraf) și fără a trunchia cuvintele. O linie este prea scurtă dacă primul cuvânt din linia următoare ar fi încăput în ea fără să depășească max_line_length.

Atunci când două linii l1 și l2 sunt concatenate în urma unei operații wrap, rezultatul obținut va fi “l1` l2`” unde l1` este l1 fără trailing whitespace, iar l2` este l2 fără starting whitespace.

Un cuvânt este orice grupare de caractere încadrată de whitespace (spațiu, tab, newline). Spre exemplu, într-un text dat, “după-amiază” va fi considerat un singur cuvânt și nu va fi trunchiat.

Fie următoarele fișiere de intrare pe care se aplică operația W 60:

in1.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo. Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi mauris massa, aliquam sed eros in, fringilla accumsan neque. Quisque blandit lobortis purus vitae gravida.
 
Morbi sit amet euismod leo. Quisque in hendrerit turpis, ac fringilla ante. Sed id mi bibendum, scelerisque arcu vel, rutrum nibh.
in2.txt
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Integer elementum, ipsum sit
amet vulputate semper, orci
justo condimentum felis, eu
lobortis metus quam ac mauris.
Mauris sed pharetra leo. Morbi
mollis nunc eu velit tincidunt
ullamcorper. Vestibulum finibus
tellus ac lobortis porttitor.
Integer a lacus nisi. Morbi
mauris massa, aliquam sed eros
in, fringilla accumsan neque.
Quisque blandit lobortis purus
vitae gravida.
 
Morbi sit amet euismod leo.
Quisque in hendrerit turpis,
ac fringilla ante. Sed id mi
bibendum, scelerisque arcu vel,
rutrum nibh.

Fișierul obținut în ambele cazuri va fi:

out.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Integer elementum, ipsum sit amet vulputate semper, orci
justo condimentum felis, eu lobortis metus quam ac mauris.
Mauris sed pharetra leo. Morbi mollis nunc eu velit
tincidunt ullamcorper. Vestibulum finibus tellus ac lobortis
porttitor. Integer a lacus nisi. Morbi mauris massa, aliquam
sed eros in, fringilla accumsan neque. Quisque blandit
lobortis purus vitae gravida.
 
Morbi sit amet euismod leo. Quisque in hendrerit turpis, ac
fringilla ante. Sed id mi bibendum, scelerisque arcu vel,
rutrum nibh.

Operațiile se efectuează incremental, deci trebuie să aveți în vedere faptul că operația wrap modifică numărul de linii și lungimea lor atunci când aplicați următoarele operații din comandă.

Center text

C [start_line [end_line]]

Operația center folosește ca referință cea mai lungă linie din fișier (fără trailing whitespace) și adaugă spații la începutul liniilor care sunt mai scurte pentru a le centra.

Fie dat următorul fișier de intrare pe care se aplică operația C:

in.txt
Lorem ipsum
 
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
mauris massa, aliquam sed eros in, fringilla accumsan neque.
Quisque blandit lobortis purus vitae gravida.

Fișierul obținut va fi:

out.txt
                            Lorem ipsum
 
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
 felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
   Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
 finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
   mauris massa, aliquam sed eros in, fringilla accumsan neque.
           Quisque blandit lobortis purus vitae gravida.

Align left

L [start_line [end_line]]

Operația align left aliniază liniile precizate la marginea din stânga.

Fie dat următorul fișier de intrare pe care se aplică operația L:

in.txt
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
  Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
mauris massa, aliquam sed eros in, fringilla accumsan neque.
         Quisque blandit lobortis purus vitae gravida.

Fișierul obținut va fi:

out.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
mauris massa, aliquam sed eros in, fringilla accumsan neque.
Quisque blandit lobortis purus vitae gravida.

Align right

R [start_line [end_line]]

Operația align right folosește ca referință cea mai lungă linie din fișier (fără trailing whitespace) și adaugă spații la începutul liniilor care sunt mai scurte pentru a le alinia la marginea din dreapta.

Fie dat următorul fișier de intrare pe care se aplică operația R:

in.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
mauris massa, aliquam sed eros in, fringilla accumsan neque.
Quisque blandit lobortis purus vitae gravida.

Fișierul obținut va fi:

out.txt
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
 felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
      Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
 finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
      mauris massa, aliquam sed eros in, fringilla accumsan neque.
                     Quisque blandit lobortis purus vitae gravida.

[BONUS] Justify

J [start_line [end_line]]

Operația justify folosește ca referință cea mai lungă linie din fișier și distribuie în mod echilibrat spații în interiorul liniilor mai scurte pentru ca acestea să ajungă la aceeași lungime și să fie aliniate atât la dreapta, cât și la stânga.

Fie dat următorul fișier de intrare pe care se aplică operația J:

in.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
finibus tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
mauris massa, aliquam sed eros in, fringilla accumsan neque.
Quisque blandit lobortis purus vitae gravida.
 
    Morbi sit amet euismod leo. Quisque in hendrerit turpis, ac
fringilla ante. Sed id mi bibendum, scelerisque arcu vel,
rutrum nibh.

Un posibil fișier obținut va fi:

out.txt
Lorem  ipsum dolor sit amet, consectetur adipiscing elit.  Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis,  eu lobortis metus quam ac mauris. Mauris sed pharetra leo.
Morbi  mollis  nunc  eu velit  tincidunt  ullamcorper.  Vestibulum
finibus  tellus ac lobortis porttitor. Integer a lacus nisi. Morbi
mauris  massa,  aliquam  sed  eros in,  fringilla accumsan  neque.
Quisque blandit lobortis purus vitae gravida.
 
Morbi  sit  amet  euismod  leo. Quisque in  hendrerit  turpis,  ac
fringilla   ante.  Sed  id  mi  bibendum,  scelerisque  arcu  vel,
rutrum nibh.

Ultimei linii dintr-un paragraf nu i se aplică operația justify, ci doar align left.

Pot exista mai multe soluții pentru această problemă. Orice soluție în care lungimea liniilor și alinierea sunt corecte și spațiile sunt distribuite echilibrat (nu există într-o linie grupări de spații între care diferența de lungime să fie mai mare ca 1) este considerată corectă. Puteți presupune că spațiile din fișierul inițial sunt deja distribuite echilibrat.

Exemplu de rezolvare incorectă (ultimul paragraf din textul de mai sus):

Morbi     sit amet euismod leo. Quisque in hendrerit turpis,    ac
fringilla      ante. Sed id mi bibendum, scelerisque     arcu vel,
rutrum nibh.

Paragrafe

P indent_length [start_line [end_line]]

Această operație realizează indentarea automată a paragrafelor din intervalul precizat (dacă există), cu indent_length spații (maxim 8). Se va indenta doar prima linie din fiecare paragraf.

Un paragraf nou este marcat prin două sau mai multe caractere newline (“\n\n”).

Fie dat următorul fișier de intrare pe care se aplică operația P 4:

in.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris.
 
Mauris sed pharetra leo.
 
Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
finibus tellus ac lobortis porttitor. Integer a lacus nisi.

Fișierul obținut va fi:

out.txt
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
elementum, ipsum sit amet vulputate semper, orci justo condimentum
felis, eu lobortis metus quam ac mauris.
 
    Mauris sed pharetra leo.
 
    Morbi mollis nunc eu velit tincidunt ullamcorper. Vestibulum
finibus tellus ac lobortis porttitor. Integer a lacus nisi.

Liste

I list_type special_character [start_line [end_line]]

Această operație formatează liniile corespunzătoare ca pe o listă (aliniată la stânga) a cărei indici sunt definiți în funcție de parametrii list_type și special_character.

Parametrul list_type indică tipul listei:

În funcție de tipul listei, parametrul special_character indică:

Caracterele speciale folosite vor fi întotdeauna urmate de spațiu.

Fiind dat fișierul:

in.txt
apples
oranges
cherries

Observați câteva exemple de operații și fișierele rezultate:

I n .
out.txt
1. apples
2. oranges
3. cherries
I a )
out.txt
a) apples
b) oranges
c) cherries
I A .
out.txt
A. apples
B. oranges
C. cherries
I b -
out.txt
- apples
- oranges
- cherries
I b *
out.txt
* apples
* oranges
* cherries

Puteți folosi funcția sprintf pentru formatare.

Se știe că nu vor exista niciodată mai mult de 26 de elemente în listă, așadar în cazul indicilor alfabetici, nu se va depăși niciodată indicele 'Z'.

Liste ordonate

O list_type special_character ordering [start_line [end_line]]

Această operație funcționează exact la fel ca operația precedentă I (formatează liniile corespunzătoare ca pe o listă a cărei indici sunt definiți în funcție de parametrii list_type și special_character), dar în plus face și ordonarea alfabetică a elementelor din listă.

Parametrul ordering indică dacă ordonarea se face alfabetic sau invers alfabetic, putând lua valorile:

Fiind dat fișierul:

in.txt
Monica
Erica
Rita
Tina
Sandra
Mary
Jessica

Observați cele două exemple de operații și fișierele rezultate:

O n . a
out.txt
1. Erica
2. Jessica
3. Mary
4. Monica
5. Rita
6. Sandra
7. Tina
O b - z
out.txt
- Tina
- Sandra
- Rita
- Monica
- Mary
- Jessica
- Erica

Tratarea cazurilor speciale

  • Parametri de tip întreg: max_line_length, start_line, end_line, indent_length
  • Parametri de tip caracter: list_type, special_character, ordering

Punctaj

TOTAL: 180p

Trimitere temă

Tema va fi trimisă folosind vmchecker, cursul Programarea Calculatoarelor (CB & CD).
Găsiți checker-ul aici.

Atenție! Checker-ul verifică atât fișierul obținut, cât și stdout. Nu trebuie să afișați nimic la stdout, în afară de cele 3 mesaje de eroare precizate în secțiunea Tratarea cazurilor speciale.

Formatul arhivei va fi următorul:

  1. fișier(ele) .c (și fișiere .h - dacă este cazul).
  2. Un fișier Makefile (detalii aici) care să conțină următoarele reguli:
    1. build: creează executabilul aferent (numele executabilului: format_text)
    2. run: rulează executabilul aferent
    3. clean: șterge fișierele obiect/executabile create.
  3. Un fișier README în care vă descrieți rezolvarea temei.

Este necesară scrierea numelui și a grupei atât în fișierul README, cât și în toate fișierele sursă pe care le adăugați în arhiva temei.

Observații

Listă depunctări (neexhaustivă)

Referințe