Tema 2 - Formatare text

Responsabili

Informații

  • Data publicare: 17 Noiembrie 2018
  • Deadline Soft: 11 Decembrie 2018 (23:55)
  • Deadline Hard: 16 Decembrie 2018 (23:55)

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

Obiective

  • utilizarea tablourilor
  • utilizarea funcțiilor de manipulare a șirurilor de caractere
  • verificarea validității datelor de intrare

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 → listă numerotată
  • a|A → listă alfabetică (cu litere mici sau mari)
  • b → bullet list

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

  • caracterul imediat următor indicelui numeric/alfabetic
  • caracterul folosit pe post de bullet

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:

  • a → sortare alfabetică normală (de la A la Z)
  • z → sortare alfabetică inversă (de la Z la A)

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

  • Dacă parametrul start_line este mai mare decât numărul de linii din fișier (atenție, nu neapărat din fișierul original! numărul de linii se poate modifica pe măsură ce se aplică operațiile) , operația este ignorată.
  • Dacă parametrul end_line este mai mare decât numărul de linii din fișier, dar parametrul start_line este valid, se va efectua operația de la start_line până la sfârșitul fișierului (ca și cum end_line nu ar fi fost precizat).
  • Dacă valoarea parametrului max_line_length de la operația wrap este mai mică decât lungimea celui mai lung cuvânt din fișierul inițial, se va afișa la stdout mesajul “Cannot wrap!”, iar fișierul obținut va fi identic cu fișierul inițial.
  • În cazul în care comanda conține mai mult de 10 operații, se va afișa la stdout mesajul “Too many operations! Only the first 10 will be applied.”, iar fișierul obținut va avea aplicate doar primele 10 operații din comandă.
  • Se va afișa la stdout mesajul “Invalid operation!”, iar fișierul obținut va fi identic cu fișierul inițial, dacă:
    • unul sau mai mulți parametri nu are tipul corect sau are o valoare invalidă (spre exemplu list_type cu o altă valoare decât cele precizate);
    • o operație invalidă este folosită (operațiile valide sunt W, C, L, R, J, P, I, O și au maximum 20 de caractere);
    • un număr incorect de parametri este precizat pentru o operație (atenție la parametrii opționali);
    • parametrul start_line este mai mare ca parametrul end_line.

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

Punctaj

  • [30p] Wrap text
  • [5p] Center
  • [5p] Align left
  • [5p] Align right
  • [30p] Justify (bonus)
  • [5p] Paragrafe
  • [10p] Liste
  • [20p] Liste ordonate
  • [45p] Operații combinate
  • [15p] Tratarea operațiilor invalide
  • [10p] README și Coding Style.

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

  • Nu folosiți variabile globale.
  • Fiți consistenți în ceea ce privește Coding Style-ul.
  • Nu este nevoie să folosiți alocare dinamică.
  • Fișierele obținute nu trebuie să conțină trailing whitespace (cu excepția situației în care aveți o operație invalidă). În urma unei operații goale (””), fișierul obținut va avea același conținut ca cel inițial, dar nu va conține trailing whitespace.

Listă depunctări (neexhaustivă)

  • o temă care nu compilează și nu a rulat pe vmchecker nu va fi luată în considerare
  • o temă care nu rezolvă cerința și trece testele prin alte mijloace nu va fi luată în considerare
  • [-1.0]: warning-uri la compilare (este obligatorie folosirea în fișierul Makefile a flag-ului de compilare -Wall pentru regula build)
  • [-1.0]: numele variabilelor nu sunt sugestive
  • [-1.0]: linii mai lungi de 80 de caractere
  • [-1.0]: cod nemodular, funcții prea lungi (inclusiv main)
  • [-5.0]: abordare ineficientă
    • în cadrul cursului de programare nu avem ca obiectiv rezolvarea în cel mai eficient mod posibil a programelor; totuși, ne dorim ca abordarea să nu fie una ineficientă, de genul să nu folosiți instrucțiuni repetitive acolo unde clar era cazul, etc.

Referințe

programare/teme_2018/tema2_2018_cbd.txt · Last modified: 2018/12/10 10:56 by ioana.alexandru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0