momente şi schiţe de informatică şi matematică
To attain knowledge, write. To attain wisdom, rewrite.

Asupra unui orar școlar (II)

R
2026 jul

În [1] plecasem de la un orar în format "PDF 1.7 tagged" descărcat mai demult de pe site-ul unei școli și am desprins muncitorește datele pentru ziua de "Luni", constituind fișierul "Lu.csv"; ar urma poate, să ne ocupăm la fel (citind ce vedem afișat de fișierul PDF și tastând într-un fișier-text) și de datele orarului pe celelalte zile…
Dar oare de ce descărcasem acum mai bine de un an, fișierul PDF respectiv — nu cumva deja ne vom fi ocupat între timp, de datele respective? Căutând prin articolele din 2025, am găsit [2] în care într-adevăr, obținusem deja (tot "muncitorește") fișierele în format CSV corespunzătoare orarelor pe fiecare zi.

Iar în [2] tastasem și disciplinele, după fișierul PDF al claselor, desemnând apoi profesorii după disciplina principală a fiecăruia. Și în [1] și în [2] ne-am ocupat numai de reducerea numărului de ferestre din orarul original, cu observația că în [1] ne-am bazat pe pachetul refitgaps constituit între timp (și ajuns pe CRAN).

Aici vom proceda ca în [1], ignorând disciplinele pe care erau încadrați profesorii în școala respectivă și vom formula un nou orar, echilibrat — spre deosebire de orarul original (cel pozat de fișierele PDF), în care există profesori cu una sau două ore într-o zi și cu 6 ore în alte zile (și profesori care fac 10 ore în numai două zile), precum și clase (parcă toate) care au în câte o zi mai multe ore cu câte un același profesor (fie pe o aceeași disciplină, "Română", "Matematică" etc., fie pe discipline diferite — dar cum am zis, ignorăm aici disciplinele, mai ales că sunt și foarte multe în școala respectivă, vreo 45 de "discipline", multe desemnate criptic "BC", "CPS", "CG", "PC" etc.).

Vrând acum să desemnăm profesorii în cel mai simplu mod, anume după numărul de ordine în lista alfabetică a acestora, nu putem refolosi (direct) setul tuturor lecțiilor prof|cls|ora obținut în [2] (în care "Fi2|..." de exemplu, reprezintă o lecție a unui profesor de "Fizică" și am avea de reconstituit "numărul de ordine" al acestuia). Cel mai simplu este să plecăm iarăși, de la fișierele CSV în care am scris orarele zilelor.

Dar nu putem refolosi direct, fișierele CSV rezultate în [2] — fiindcă pe fiecare dintre acestea înregistrasem numai profesorii care au ore în ziua respectivă. În Lu.csv din [1] avem toți profesorii (inclusiv cei "liberi"), în ordine alfabetică — însă în 25mar/Lu.csv avem numai pe cei care au ore în ziua "Luni" (nu și pe cei liberi); am putea reconstrui fișierul CSV din [2], pentru a include și liniile celor liberi existente în fișierul de același nume din [1], folosind programele utilitare diff și patch:

diff -u ../25mar/Lu.csv Lu.csv > DF.txt
patch ../25mar/Lu.csv < DF.txt

Însă nu putem proceda la fel (folosind diff și patch) pentru celelalte zile, fiindcă în [1] nu avem decât fișierul CSV pentru ziua "Luni"… În schimb, pe baza fișierului "Lu.csv" din [1] putem constitui (sub R) un "vector cu nume" care asociază fiecărui profesor numărul de ordine al acestuia în lista ordonată alfabetic a tuturor profesorilor:

library(tidyverse)
W <- read.csv("Lu.csv") %>% select(prof)
prof_cod <- c(paste0("p0", 1:9), paste0("p", 10:nrow(W))) %>%
            setNames(W$prof)
> sample(prof_cod, size=3)  # exemplificare (vector cu nume)
      Ciocan Catalina  Barladeanu Alina Ganea-Popa Denisa   # nume
                "p17"             "p09"             "p33"   # cod

De observat că pentru primii 9 profesori codul are prefixul "p0" (și nu p, ca în [1]); astfel toți profesorii sunt desemnați prin "coduri" de o aceeași lungime, ceea ce este totuși important: funcția refitgaps::have_gaps() (pentru orarele individuale cu ferestre) pretinde coduri de lungime 3 la cei neangajați în cuplaje (și 6, pentru cuplaje).

Copiem în directorul curent fișierele CSV din [2]:

cp ../25mar/{Lu,Ma,Mi,Jo,Vi}.csv  .

le transformăm pe fiecare (folosind lapply()) în obiecte de tip "data.frame" (prin read.csv()) și înlocuim numele de profesori prin codurile din vectorul prof_cod, apoi prin pivot_longer() obținem setul tuturor lecțiilor zilei curente prof|ora|cls din care (fiindcă nu ne mai interesează orarul original) excludem câmpul "ora"; în final, reunim (prin rbind()) seturile pe zile rezultate, obținând setul LSS al tuturor lecțiilor prof|cls:

Zile <- c("Lu", "Ma", "Mi", "Jo", "Vi")
lDF <- lapply(Zile, function(Zi) {
    Z <- read.csv(paste0(Zi, ".csv")) %>%
         mutate(prof = as.character(coalesce(prof_cod[prof], prof)))
    Z %>% pivot_longer(cols = 2:ncol(.), 
                       names_to = "ora", values_to = "cls") %>%
          filter(!is.na(.$cls) & cls != "") %>%
          select(prof, cls)
})
LSS <- do.call(rbind, lDF)
saveRDS(LSS, "lessons.RDS")
    > str(LSS)  # inspectăm setul tuturor lecțiilor (1172 lecții):
    tibble [1,172 × 2] (S3: tbl_df/tbl/data.frame)
     $ prof: chr [1:1172] "p01" "p01" "p01" "p01" ...
     $ cls : chr [1:1172] "10D" "10D" "9G" "9G" ...

Este de subliniat că a fost necesar să folosim mai sus coalesce(): vectorii prof_cod și Z$prof au lungimi diferite; iar ambalând sub as.character(), evităm înregistrarea inutilă a numelui profesorului căruia vectorul cu nume prof_cod îi asociază codul respectiv.

Subliniem că setul LSS trebuie verificat: dacă există linii pe care în câmpul prof apare NA, atunci înseamnă că în vreunul dintre fișierele CSV de la care am plecat, vreun nume de profesor a fost "stâlcit" și nu i s-a putut asocia un cod (iar în acest caz, funcția days2lessons::mount_days() angajată mai jos va produce doar o anumită eroare).

Vrem să repartizăm pe zile cele 1172 de lecții, în mod echilibrat; apoi, să repartizăm lecțiile dintr-o aceeași zi pe orele 1:7 ale zilei (iar în final, vom reduce pe cât se poate, numărul de ferestre apărute pe orarele zilnice).

Pentru ajustarea interactivă ulterioară a unor distribuții individuale vom avea de consultat tabelele de repartizare a lecțiilor pe profesori și pe clase:

> table(LSS$prof) %>% sort() 
p45 p41 p07 p30 p37 p36 p34 p53 p16 p38 p49 p04 p05 p10 p15 p39 p40 p50 p14 p03 
  3   5   6   6   6   8   9   9  10  17  17  18  18  18  18  18  18  18  19  20 
p06 p09 p11 p17 p18 p24 p44 p51 p54 p01 p08 p12 p13 p21 p22 p23 p27 p28 p35 p46 
 20  20  20  20  20  20  20  20  20  21  21  21  21  21  21  21  21  21  21  21 
p20 p25 p31 p32 p33 p42 p47 p52 p02 p43 p19 p26 p48 p29 
 22  22  22  22  22  22  22  22  23  23  24  24  24  26 
> table(LSS$cls)  
10A 10B 10C 10D 10E 10F 10G 10H 10I 10J 11A 11B 11C 11D 11E 11F 11G 11H 11I 11J 
 30  30  30  30  30  30  30  30  30  30  31  31  31  31  31  31  31  31  31  31 
11K 12A 12B 12C 12D 12E 12F 12G 12H 12I  9A  9B  9C  9D  9E  9F  9G  9H  9I 
 31  29  29  29  29  29  29  29  29  29  30  30  30  30  30  30  30  30  30 

Să observăm (din primul tabel) că în mod normal oricare profesor trebuie să aibă cel mult 6 ore/zi (cel cu cel mai mare număr total de ore, "p29", ar avea în mod normal 4 zile cu câte 5 ore și o zi cu 6 ore; ceilalți n-ar trebui să depășească 5 ore/zi).

Funcția mount_days() din pachetul days2lessons produce o repartizare pe zile a lecțiilor prof|cls respective, în care clasele și profesorii au distribuții omogene sau eventual, cvasi-omogene (numărul de ore pe zi diferă fie cu 1 fie cu 2, de la o zi la alta):

LS <- readRDS("lessons.RDS")
show_time <- function(NL = " ")
    cat(strftime(Sys.time(), format="%H:%M:%S"), NL)
library(days2lessons)
show_time(" ")
    DZ <- mount_days(LS)
show_time("\n")
saveRDS(DZ, "by_days.RDS")

Investigăm omogenitatea distribuțiilor (rezultate de această dată în mai puțin de un minut):

07:20:02  07:20:55  # durata: sub un minut
> table(DZ$zl) 
     Lu  Ma  Mi  Jo  Vi 
    235 231 233 237 236  # totaluri ore/zi (distribuție neomogenă) 
> table(DZ[c("cls", "zl")]) 
         zl
    cls   Lu Ma Mi Jo Vi
      10A  6  6  6  6  6
      10B  6  6  6  6  6
      10C  6  6  6  6  6
# ...
      11J  6  6  6  7  6
      11K  6  6  7  6  6
      12A  6  5  6  6  6
      12B  6  6  6  6  5
# ...  # toate clasele au distribuții omogene
> table(DZ[c("prof", "zl")]) 
         zl
    prof  Lu Ma Mi Jo Vi
      p01  3  5  4  4  5  # distribuție cvasi-omogenă
      p02  1  1  1  2  2
      p03  4  4  4  6  5
      p04  1  2  0  1  2
# ...
      p39  5  4  5  4  3
      p40  5  4  5  6  6
      p41  0  1  1  2  2
      p42  4  5  5  4  4  # distribuție omogenă
      p43  4  4  4  5  5
      p44  4  5  5  4  4
      p45  2  2  2  0  0
# ...  # la unii profesori distribuția este cvasi-omogenă

Subliniem că dacă repetăm execuția secvenței de mai sus, vom obține (într-un timp care diferă de la o execuție la alta, putând ajunge și la câteva minute) o altă distribuție DZ, cu alte caracteristici de omogenitate…

Dacă vrem, putem ajusta interactiv distribuția pe zile rezultată; de exemplu, pentru a omogeniza totalurile de ore/zi — adică pentru a avea 234 ore/zi în trei zile și 235 ore/zi în celelalte două zile — ar trebui să mutăm 2 lecții din ziua Jo (pe care în DZ apar 237 ore/zi) și 2 lecții din ziua Vi, în zilele Ma și Mi (și avem de văzut care lecții ar fi convenabil să le mutăm). Prin pachetul recastlessons putem explora și ajusta interactiv (lucrând în consola R) distribuția pe zile respectivă (v. [3]); subliniem totuși că am putea să ne mulțumim și cu distribuțiile cvasi-omogene rezultate până acum (faptul că unii profesori au într-o zi cu două ore mai mult ca în celelalte, nu pare a fi deranjant)

Clasele a 11-a sunt singurele care au și zile cu 7 ore/zi, iar distribuțiile numărului de ore/zi pentru acestea sunt:

> table((DZ %>% filter(grepl("11", cls)))[c("cls", "zl")])
         zl
    cls   Lu Ma Mi Jo Vi
      11A  7  6  6  6  6
      11B  6  6  6  6  7
      11C  6  6  6  6  7
      11D  6  6  6  6  7
      11E  6  6  6  6  7
      11F  6  6  6  7  6
      11G  6  6  6  6  7
      11H  7  6  6  6  6
      11I  6  6  6  7  6
      11J  6  6  6  7  6
      11K  6  6  7  6  6

Clasa 11I are 7 ore în ziua Jo, iar distribuțiile profesorilor care la clasa respectivă au ore Jo dar nu și Ma este:

library(recastlessons)  # funcțiile de investigare|ajustare interactivă
> prof_2days(DZ, "11I", "Jo", "Ma") 
         zl
    prof  Lu Ma Mi Jo Vi
      p03  4  4  4  6  5
      p62  0  1  2  1  0
      p72  4  3  5  3  5

Mutând lecția p03|11I|Jo în ziua Ma, prin:

> DZ <- change_day(DZ, "p03", "11I", "Jo", "Ma")

distribuția lui p03 devine omogenă (anume, (4 5 4 5 5)), iar distribuția totalurilor începe să se omogenizeze, devenind (235 232 233 236 236).

Analog, pentru clasa 11J:

> prof_2days(DZ, "11J", "Jo", "Ma") 
         zl
    prof  Lu Ma Mi Jo Vi
      p13  4  2  3  4  4
      p32  1  1  2  3  3
      p64  4  5  5  4  4
      p57  4  3  5  5  5
> DZ <- change_day(DZ, "p57", "11J", "Jo", "Ma")

p57 capătă și el o distribuție omogenă, iar totalurile pe Ma și Jo devin 233 și 235.

Analog, mutăm p50|11E din ziua Vi în ziua Ma și p25|11D din ziua Vi în ziua Mi. Astfel, distribuția totalurilor devine omogenă, cu 235 de ore pe Lu și Jo, respectiv 234 de ore în celelalte zile; în plus, s-au omogenizat încă două distribuții individuale (la p50 și p25).

Au rămas distribuții individuale cvasi-omogene:

Bad <- prof_bad_dis(DZ)
Nq <- ncol(Bad)  # = 40 (cu mai mult de 8 ore, distribuite cvasi-omogen)
Bad[, sample(1:Nq, size = Nq/3)]  # eșantion ilustrativ
       p07 p52 p65 p24 p37 p21 p31 p09 p59 p26 p12 p38 p13
    Lu   5   1   5   5   5   3   3   5   4   4   5   5   4
    Ma   3   1   5   4   4   4   1   5   4   5   4   5   2
    Mi   4   2   4   4   6   5   2   3   4   4   5   3   3
    Jo   3   3   4   3   5   4   2   4   4   6   3   4   4
    Vi   3   2   6   4   4   3   2   3   2   5   3   4   4

Dacă vrem, putem să omogenizăm interactiv o mare parte dintre aceste 40 de distribuții cvasi-omogene (iar aici procedăm întâi altfel decât în [2]).

Să extragem din setul Bad distribuțiile care conțin 6 ore măcar într-o zi:

> Filter(function(P) any(P == 6), Bad)
       p26 p36 p37 p40 p65
    Lu   4   4   5   5   5
    Ma   5   4   4   4   5
    Mi   4   6   6   5   4
    Jo   6   4   5   6   4
    Vi   5   4   4   6   6

Să observăm că p26 și p36 ar putea interschimba o clasă (și rămâne să vedem care clasă) între zilele Mi și Jo, astfel încât ambele distribuții să devină omogene. Clasele distribuite lor pe fiecare zi sunt:

> cls2prof(DZ, "p26") 
       p26
    Lu "10J 11F 12C 12E"       
    Ma "11C 11E 11F 12C 12E"   
    Mi "10C 11C 11E 9B"        
    Jo "10C 10J 11F 12C 12E 9B"
    Vi "10C 10J 11C 11E 9B"    
> cls2prof(DZ, "p36") 
       p36
    Lu "11B 12C 12F 12I"        
    Ma "11A 11I 12H 9D"         
    Mi "10G 11B 11D 11I 12C 12H"
    Jo "10I 12I 9D 9E"          
    Vi "11A 11D 12F 9E" 

Fiindcă 12C apare la ambii profesori, la primul Jo dar nu și Mi, iar la al doilea invers, Mi dar nu și Jo — putem schimba între ei ora la această clasă:

> DZ <- change_day(DZ, "p26", "12C", "Jo", "Mi")
> DZ <- change_day(DZ, "p36", "12C", "Mi", "Jo")
> saveRDS(DZ, "by_days.RDS")  # salvăm din când în când, modificările

O situație analogă avem pentru p37 și p65 (v. tabelul extras din Bad mai sus); investigând clasele repartizate acestora în zilele Mi și Vi, găsim o clasă care poate fi mutată între aceste zile la ei — omogenizând astfel și distribuțiile acestora.

Însă procedeul acesta, de a evidenția două coloane din Bad pe care în două zile să apară la unul să zicem (3 5) și la celălat invers (5 3), poate conduce la omogenizarea distribuțiilor numai dacă există o clasă care apare și la unul și la celălalt, dar în câte una singură (și nu aceeași) dintre cele două zile…
Funcția prof_swap() simplifică investigațiile necesare, furnizând pentru un profesor dat lista celor cu care el poate interschimba o anumită clasă între două zile precizate; de exemplu, să omogenizăm distribuția lui p40 (singura rămasă cvasi-omogenă, din tabelul extras mai sus din Bad):

> cls2prof(DZ, "p40") 
       p40
    Lu "11A 11F 11H 11K 12B"    
    Ma "11F 11G 12E 12F"        
    Mi "11B 11G 11H 12B 9I"     
    Jo "10D 11A 12F 12H 12I 9I" 
    Vi "10D 11B 11K 12E 12H 12I" 
> prof_swap(DZ, "p40", "Vi", "Ma") 
[[1]]
       p39                 
    Lu "10C 11C 11F 12C 9H"
    Ma "10B 10D 9B 9C"     
    Mi "10E 10G 11B 12G 9D"
    Jo "10A 10I 9G 9I"     
    Vi "10F 11G 12E"       
 # ...
[[6]]
       p59              
    Lu "11E 11J 12A 12B"
    Ma "10H 11D 12F 12H"
    Mi "11A 11K 12I 9E" 
    Jo "10J 11H 12D 9A" 
    Vi "11I 9F"         

Între p40 și p39 putem interschimba clasa 10D, între zilele Vi și Ma — dar astfel distribuția lui p39 ar rămâne cvasi-omogenă. Însă vedem că putem interschimba cu p59 clasa 12H, omogenizând astfel și distribuția lui p40 și pe cea a lui p59:

> DZ <- change_day(DZ, "p40", "12H", "Vi", "Ma")
> DZ <- change_day(DZ, "p59", "12H", "Ma", "Vi")
> saveRDS(DZ, "by_days.RDS")

Până la urmă (într-un timp care depinde de ambiție și experiență de lucru), am omogenizat toate distribuțiile individuale cu mai mult de 8 ore (folosind ca mai sus, cls2prof(), prof_swap() și change_day(), iar din când în când, saveRDS()); apoi ne-am ocupat și de cele cu număr mic de ore, reușind să le condensăm în cât mai puține zile — încât în final în Bad, drept "cvasi-omogene", au rămas numai acestea:

> (Bad <- prof_bad_dis(DZ, at_least = 3))
       p04 p14 p16 p18 p35 p41 p45 p46 p47 p52 p56 p62
    Lu   0   2   0   2   0   0   2   0   0   0   3   0
    Ma   2   2   2   2   2   0   2   2   1   2   0   0
    Mi   0   0   0   0   3   2   2   2   1   2   2   2
    Jo   2   0   2   3   2   2   0   3   2   3   0   2
    Vi   2   0   2   2   0   2   0   2   2   2   0   0

Subliniem că distribuția lui p47 n-a putut fi condensată, fiindcă are 4 ore la o clasă și 2 ore la o altă clasă (și am vrut ca și în acest caz, să respectăm regula de a nu intra de două ori pe zi la o aceeași clasă — excepția fiind numai aceea când ar avea mai mult de 5 ore la clasa respectivă).

Dacă omitem 0 (reprezentând "zi liberă") din cadrul celor 12 distribuții din Bad redate mai sus, putem zice că și acestea sunt "omogene"; deci în acest moment, datele prof|cls|zl din setul DZ constituie o repartizare pe zile a tuturor celor 1172 de lecții, în care variabila "număr de ore/zi" are o distribuție uniformă față de cele 5 zile de lucru, față de fiecare clasă, față de fiecare profesor și chiar, față de fiecare disciplină (având în vedere că nu avem lecții multiple prof|cls|zl, decât în cazurile firești când prof are la clasa cls mai mult de 5 ore/săptămână).
Frumoasă repartizare am reușit! Dar… s-ar putea să ne coste, mai târziu; după ce vom aloca lecțiile dintr-o aceeași zi pe orele 1:7 ale zilei respective, va trebui să ne ocupăm de reducerea numărului de ferestre apărute la profesori și de regulă vom constata că nu prea putem reduce numărul total de ferestre, mai jos de vreo 7% din totalul lecțiilor (ceea ce zicem că este mult). Iar una dintre cauze este tocmai omogenizarea excesivă a repartizării pe zile; dacă în loc să condensăm distribuțiile cu mai puțin de 9 ore, cum am făcut mai sus, le omogenizam (de exemplu, în loc de (2 2 0 0 0) cum i-ar conveni profesorului, preferam (1 1 1 1 0)), atunci ferestrele ar fi fost mai ușor de evitat.

Deocamdată să vedem cum am putea reda aici, cât mai concis, repartizarea pe zile obținută în DZ (și salvată în fișierul "by_days.RDS"):

library(tidyverse)
Bd <- readRDS("by_days.RDS")
# > glimpse(Bd)  # inspectăm în consolă repartizarea pe zile
    Rows: 1,172  Columns: 3
    $ prof <ord> p42, p54, p37, p37, p37, p16, p16, p16, p06, ...
    $ cls  <chr> "10A", "10A", "10A", "10A", "10A", "10A", ...
    $ zl   <fct> Ma, Vi, Jo, Mi, Lu, Ma, Vi, Jo, Mi, Lu, Ma, Vi, ...
Zile <- levels(Bd$zl)  # $zl și $prof sunt de tip "factor"
tidy_as_tsv <- function(D) { # D este un set/subset de lecții
    Dz <- D %>% split(.$zl)
    Z <- map(Zile, function(z) {
             map_dfr(Dz[[z]] %>% split(.$prof), function(L)
                  data.frame(prof = L$prof[1],
                             cls = paste(L$cls, collapse=" "))
             )
         }) %>% setNames(Zile)
    data.frame(prof = levels(D$prof), 
               Lu = Z$Lu$cls, Ma = Z$Ma$cls, Mi = Z$Mi$cls, 
               Jo = Z$Jo$cls, Vi = Z$Vi$cls)
}

Funcția tidy_as_tsv() primește un set de lecții prof|cls|zl, îl desparte pe zile și produce un "tabel" care listează pe fiecare zi clasele repartizate câte unui profesor; am putea afișa tabelul produs, dar liniile ar fi prea lungi — de aceea, în prealabil, "reducem" numele claselor, prefixând litera cu "0", "1" sau "2" pentru clasele a 10-a, a 11-a, respectiv a 12-a (în loc de "10A" de exemplu, vom avea "0A"):

B <- Bd %>% mutate(cls = gsub("(.)(.)(\\w)", "\\2\\3", cls, perl=TRUE))
Bd_tsv <- tidy_as_tsv(B)
# > glimpse(Bd_tsv)  # inspectăm
    Rows: 72  Columns: 6
    $ prof  "p01", "p02", "p03", "p04", "p05", "p06", ...
    $ Lu    "0D 2I 9F 9G", "9B", "0E 0J 9A 9E", "", "2A 2A", ...
    $ Ma    "0F 0H 1J 9G", "9D", "0C 1I 9F 9H", "0F 0I", ...
    $ Mi    "0D 0F 0H 9F", "9G", "0A 0I 1E 2H 9I", "", "1F 2A", ...
    $ Jo    "0D 1J 2I 9F", "9A 9E", "0B 0G 9B 9C 9G", "0H 9I", ...
    $ Vi    "0F 0H 1J 2I 9G", "9C 9F", "0D 1D 1F 1G 9D", ...
write_csv(Bd_tsv, file = "Bd1.csv")

În loc să afișăm "tabelul" rezultat (încă am avea linii prea lungi), l-am scris într-un fișier-text, în format CSV; funcția următoare (în limbajul clasic AWK) ne permite să aplicăm culori distincte de la o zi la alta, pe clasele repartizate într-o aceeași zi:

# pygCSV.awk
BEGIN { FS = ","; OFS = ", "  # separatori de câmpuri la intrare/ieșire
	cul[1] = "black"; cul[2] = "green"
	cul[3] = "blue"; cul[4] = "orange"
	cul[5] = "purple"; cul[6] = "red"
}
{ for(i = 1; i <= 6; i++)
      if(length($i) > 1) $i = "<span style=\"color:"cul[i]"\">"$i"</span>"
      else $i = " "
  print
  print("<br>")
}

Lansând acest program pe fișierul CSV rezultat mai sus, obținem un fișier HTML în care clasele la fel colorate corespund unei aceleiași zile:

gawk -f pygCSV.awk  Bd1.csv > Bd.html

Redăm fișierul HTML rezultat, după ce în prealabil am ambalat liniile respective într-un <div> pe care l-am stilat cu un font "serif" (pentru lizibilitate mai bună asupra numelor claselor); în plus, am boldat virgulele separatoare:

prof, Lu, Ma, Mi, Jo, Vi
p01, 0D 2I 9F 9G, 0F 0H 1J 9G, 0D 0F 0H 9F, 0D 1J 2I 9F, 0F 0H 1J 2I 9G
p02, 9B, 9D, 9G, 9A 9E, 9C 9F
p03, 0E 0J 9A 9E, 0C 1I 9F 9H, 0A 0I 1E 2H 9I, 0B 0G 9B 9C 9G, 0D 1D 1F 1G 9D
p04, , 0F 0I, , 0H 9I, 0J 9H
p05, 2A 2A, 1D 1F 2A, 1F 2A, 1D 2A, 2A 2B 2H
p06, 0A 0B 0E 9C, 0E 0F 9B 9C, 0A 0D 0F 9A, 0C 0D 9B 9D, 0B 0C 9A 9D
p07, 0E 1A 2H 9A, 0E 1B 2H 9I, 1A 1B 2H, 1A 9A 9I, 0E 1B 9A 9I
p08, 0C 0G 1B 1C, 0C 1B 1C, 0C 0G 1C 2E, 0G 1B 1C 2E, 0G 1B 2E
p09, 0E 1E 9A 9H, 1D 1E 9A 9H, 0I 1C 1D 2D, 1C 2D 2G 9D, 0E 0I 2G 9D
p10, 9B, 9E, 9A 9C, 9F, 9G
p11, 0I 1D 1G 2D 2F, 1G 1I 2B 2D, 0I 1G 1I 2F, 0I 1D 1I 2B, 1D 2B 2D 2F
p12, 0B 0F 0J 1J, 0B 0J 1J 9A, 0J 1F 1J 9A, 0F 1J 2E 9A, 0B 0F 1A 1J
p13, 0C 1A 1G 1K, 1C 1J 1K, 0H 0I 1J, 0F 1G 1K, 0D 0J 1C 1J
p14, 9H 9I, 0A 0B, , ,
p15, 0A 1C 1D 2E, 0A 1C 1D 9D, 0A 1C 1D, 1C 1D 2E 9D, 1C 1D 9D
p16, , 0A 0I, , 0A 0I, 0A 0I
p17, 0I 1C 9G 9I, 0I 2C 9F 9I, 0I 2C 9F 9G, 0I 1F 2C 9G, 1G 2C 9F 9I
p18, 0C 0F, 0B 0H, , 0D 0E 0G, 0A 0I
p19, 0C 2I 2I 2I, 0B 0C 2I 2I, 0B 0C 1A 2I 2I, 0B 0C 2I 2I, 0B 1F 2I 2I
p20, 0J 1D 1I 2I 9A, 0J 1I 2I 9A, 0E 0J 2I 9B, 0E 1D 1I 9B, 0E 1D 9A 9B
p21, 1H 1J 2B 2C, 1H 2B 2D 9A, 1A 2A 9A 9H, 1H 2B 2F 9H, 1H 9A 9H
p22, 0G 1G 2H 9G, 0G 1G 2C 2H, 0E 1G 2C 9G, 0E 1G 9G, 0E 0G 1G
p23, 2A 9F, 0J 9B, 0G 0J, 0G 2A, 9B 9F
p24, 0A 0D 0E 0H, 0D 0E 0H 0J, 0A 0E 0H 0J, 0A 0D 0E 0J, 0A 0D 0H 0J
p25, 1D 1I 2F 9E, 1F 1I 2F 9E, 1D 1F 9E 9H, 1D 1I 2F 9H, 1F 1I 2F 9H
p26, 0J 1F 2C 2E, 1C 1E 1F 2C 2E, 0C 1C 1E 2C 9B, 0C 0J 1F 2E 9B, 0C 0J 1C 1E 9B
p27, 1C 2G, 2B 2G 2H, 1H 2G, 1B 1C 2D, 1B 2B
p28, 1E 1H 2B 2D, 1A 1B 1I 2I, 1I 2A 2B 2C 2I, 1A 1B 1E 2H, 1H 2A 2C 2D 2H
p29, 0D 1B 1K 2G 9H, 0D 1B 1K 2F, 1B 1K 2F 2G, 1B 2F 2G 9H, 0D 1B 1K 9H
p30, 0D 0G 1J 9F, 0I 1G 9G 9H, 0B 0E 2E 9I, 0F 1K 2F 2H 9E, 0C 0J 1B 1C
p31, 1I 2E, 2A 2I, 2F 2G, 1G 2C, 1E 2B
p32, 1F 1G, 1J 1K, 1C 1G, 1F 1K, 1C 1J
p33, 0H 0I 1J 9C, 0I 2B 2D 9G, 0H 0I 9C 9G, 1J 2B 2D 9C, 0H 1J 2B 2D 9G
p34, 1D 2D 9D 9G, 9D 9E 9G 9I, 1I 1K 9D 9E, 0J 9E 9G 9I, 1B 1K 2D 9I
p35, , 0F 0J, 0F 0J 2E, 0F 0J,
p36, 1B 2C 2F 2I 9D, 1A 1I 2H 9D, 0G 1B 1D 1I 2H, 0I 2C 2I 9E, 1A 1D 2F 9E
p37, 0A 1C 1G 9D 9F, 0G 1C 2G 9D, 0A 1G 2H 9D 9F, 0A 0G 1G 2G 2H, 0G 1C 2G 2H 9F
p38, 1E 1F 1K 2B 9B, 1G 2E 9B 9G, 0B 0C 2B 9A, 0J 1E 1F 1K, 1G 2E 9A 9G
p39, 0C 1C 2C 9H, 0B 0D 9B 9C, 0E 0G 1B 2G 9D, 0A 0I 9G 9I, 0F 1F 1G 2E
p40, 1A 1F 1H 1K 2B 9I, 1F 1G 2E 2F 2H, 1B 1G 1H 2B 9I, 0D 1A 2F 2H 2I, 0D 1B 1K 2E 2I
p41, , , 9C 9I, 9C 9I, 9C 9I
p42, 1A 2A 2E 2F 9E, 0A 2A 2B 2E, 0B 0C 0D 1B 2F, 2B 2D 9A 9B, 1C 2D 9C 9D
p43, 1A 1I 2C 2H, 1E 1I 2C 9A, 1E 1I 2C 9A, 1A 1G 1I 2C 2H, 1G 1I 1I 2H 9A
p44, 0F 0I 0J 9A 9B, 0C 0E 9A 9E 9H, 9B 9C 9E 9F, 0D 9C 9D 9H, 0A 0B 9D 9F
p45, 0B 0G, 0A 0C, 0D 0E, ,
p46, , 1A 1H, 0F 1H, 0F 1A 1H, 0F 1A
p47, , 2A, 2A, 1H 2A, 1H 2A
p48, 0D 1E 1F 2A, 0C 0D 1F 2A 2C, 0D 1F 2A 9H, 0C 1E 2C 9H, 0C 1E 2C 9H
p49, 1D, 2E 2F, 2F 2G, 2G, 1D 2E
p50, 1B 1F 1H 1I 2H, 1A 1B 1C 1D 1E, 1D 1E 1H 2D 9D, 0E 1B 1D 1F, 0G 1A 1F 1H 1I
p51, 0G 1K 2G 9D, 0G 1K 2G, 1K 2G 9D, 1E 1K 2G 9D, 0G 1K 2G
p52, , 1H 9E, 1H 2A, 1H 2A 9E, 2A 9E
p53, 0F 1B 2G, 1A 1H 1J, 1K 2B 2D, 1C 2A 2E, 0H 2C 2F 2I
p54, 1I 2A 2D 9D, 1D 1H 2G 2I, 1A 1F 2B 2C, 0H 9A 9C, 0A 1E 9B
p55, 0J 9E 9H, 0G 0H 0J 9F, 9E 9G 9H, 0H 0I 9F 9I, 0G 0I 9G 9I
p56, 0H 9G 9I, , 9G 9I, ,
p57, 0H 9C 9E 9G, 0A 0F 1J 9C, 0B 0C 0F 1I 1J, 0B 0H 2C 9G, 0A 0C 1I 2C 9E
p58, 0F 1A 2E 9B 9C, 0F 1E 2E 9B 9C, 1A 1D 2E 9B 9B, 0F 2B 2E 9B, 0F 1A 9B 9C
p59, 1E 1J 2B 9A, 0H 1D 2F, 1A 1K 2I 9E, 0J 1H 2D, 1I 2A 2H 9F
p60, 0H 0I 1A 1J, 0B 0I 1A 1F, 0B 0H 1F 1J, 0B 1A 1F 1J, 0H 0I 1A 1F
p61, , 0D 9I, , , 9I
p62, , , 1J 2I, 1I 2I,
p63, 0B 1B 2E 2F 9I, 1B 1K 9E 9I, 1K 2E 2F 9I, 0B 1B 1K 9E, 0B 2E 2F 9E
p64, 0F 0H 1H 9C 9F, 2D 2G 9F 9H, 1C 1J 2D 9C, 0A 1C 1J 2A 9H, 0E 1H 2A 2G
p65, 0A 0B 2G 9D 9H, 0G 1K 2G 9C 9D, 0A 0G 1K 9D 9H, 0A 0B 0G 9C, 0B 1K 2G 9C 9H
p66, 0E 2D 2D 9C, 2D 9C 9F, 2D 2D 9F, 0E 2D 9F, 0E 1G 2D 9C
p67, 0C 1E 2B 9B, 1E 1E 2B, 1E 1E 2B 9B, 0C 1E 2B, 0C 1E 1E 9B
p68, 9F, 9F, , 9F,
p69, 0A 0B 0G 0I, 0E 9B 9H 9I, 0G 0J 9C 9F, 0C 0H 9A 9D, 0D 0F 9E 9G
p70, 1G 1H 2C 2H 9I, 0E 0G 2C 9G, 0F 1D 2H 9H, 0H 1E 1F 2G 9F, 0I 0J 1K 2G
p71, 0D 2F, 0D 1J, 0D, 1J 2F, 1J 2F
p72, 1H 1K 2H 9E, 0H 1G 1H 2H, 0H 1G 1H 9E, 1G 1H 1I 2H, 0H 1H 2H 9E

Avem aici un fișier CSV, dar pigmentat prin HTML (cu dimensiune mai mică decât 20 Kb); clasele colorate cu verde corespund zilei Lu, cele colorate albastru sunt ale zilei Ma, ș.a.m.d. Bineînțeles că, dacă vrem (păi nu? de ce simplu și mic, când se poate complicat și voluminos), putem să redăm fișierul CSV respectiv sub forma unui tabel HTML înzorzonat eventual cu fel de fel de fonturi, culori și linii (precum pe fișierele PDF de la care plecasem)… Păi nu? de ce să transferăm un fișier mic (în format text, evident "independent de dispozitiv"), când putem transfera aceleași date printr-un fișier PDF ("tagged", "optimized", "secured", etc.) de vreo 10000 de ori mai voluminos (e drept că și acesta este independent de dispozitivul de redare); de ce să permitem accesul direct la datele respective, în loc să lăsăm pe cel interesat de date să muncească pentru a le decupa? Păi nu?

vezi Cărţile mele (de programare)

docerpro | Prev |