MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Formatarea șirurilor și funcția format

Pentru o formatare mai convenabilă a șirurilor, începând cu standardul C++20, biblioteca standard C++ a adăugat modulul format și, în special, funcția std::format(). Ca prim argument, funcția primește un șir de formatare. Acest șir conține orice număr de locuri rezervate {}. Al doilea și următorii parametri reprezintă argumentele care vor fi inserate în aceste locuri rezervate - în interiorul acoladelor - câte un argument pentru fiecare pereche de acolade.

Să luăm un exemplu simplu:

#include <iostream>
#include <format>

int main()
{
    int a {10};
    int b {7};
    std::cout << std::format("{} + {} = {}", a, b, a+b);
}

Aici, șirul de formatare conține trei locuri rezervate {}: "{} + {} = {}". Ca al doilea, al treilea și al patrulea parametru sunt transmise valorile care vor fi inserate în locurile rezervate în ordinea lor: primul valoare este introdusă în prima pereche de acolade, al doilea în a doua pereche și așa mai departe. În final, vom obține următorul rezultat în consolă:

10 + 7 = 17

Este important de menționat că suportul pentru această funcție poate varia în funcție de compilator, având în vedere că aceasta a fost adăugată recent în standard. De exemplu, Visual Studio o susține complet, dar în GCC (g++) suportul a fost adăugat doar începând cu versiunea 13.0. La compilarea cu Clang, poate fi necesar să adăugați flag-ul -fexperimental-library:

clang++ -std=c++20 -fexperimental-library hello.cpp -o hello

Fiecare loc rezervat poate conține diverse opțiuni de formatare, care urmează acest format:

[[fill]align][sign][#][0][width][.precision][type]

În parantezele pătrate sunt opțiuni individuale de formatare. Toate aceste opțiuni sunt aplicate diferitelor tipuri de date. Vom examina câteva dintre ele.

Specificațiile de formatare

Specificația de formatare permite setarea numărului de zecimale pentru numerele cu virgulă mobilă și a numărului de caractere afișate pentru șiruri. Ea are următorul format:

:.număr_de_zecimale

După două puncte și punctul, se specifică numărul de caractere de afișat pentru numărul respectiv:

#include <iostream>
#include <format>

int main()
{
    double sum {100.2567}; 
    std::cout << std::format("sum = {:.5}", sum);
}

În acest caz, formatarea se aplică numărului sum. Valoarea acestuia este 100.2567. În șirul de formatare este transmis specificatorul :.5, astfel că la afișare vor apărea doar primele 5 cifre ale numărului:

sum = 100.26

Este important de menționat că ultima cifră afișată este rotunjită la 1 dacă cifra care urmează este mai mare sau egală cu 5. Prin urmare, în acest caz, în loc de 100.25, consola va afișa 100.26.

Implicit, valoarea specificatorului de formatare reprezintă numărul total de cifre semnificative (în exemplul nostru, 5), inclusiv cifrele de dinainte și după virgulă. Totuși, se poate specifica și numărul de cifre după virgulă. Pentru aceasta, se adaugă litera f la specificatorul de formatare:

std::cout << std::format("sum = {:.5f}", sum);

Aici, din nou, sunt afișate 5 caractere, dar de această dată după virgulă. Deoarece numărul sum are doar 4 caractere după virgulă, pentru al cincilea caracter se adaugă 0:

sum = 100.25670

Similar, acest specificator poate fi folosit și pentru a seta numărul de caractere afișate pentru un șir de caractere. De exemplu, pentru a afișa doar primele 5 caractere dintr-un șir:

std::cout << std::format("name = {:.5}", "Tom Smith");    // name = Tom S

Parametrul width

Parametrul width permite setarea lățimii minime a câmpului. Pentru a atinge această lățime minimă, dacă este necesar, se pot adăuga caractere de completare la valoarea formatată. Ce caractere vor fi adăugate depinde de tipul valorii și de altele opțiuni de formatare. Pentru a seta explicit caracterul de completare, se utilizează parametrul fill, care precede parametrul width.

De exemplu, dacă pentru lățimea câmpului se folosește simbolul "0" (zero), atunci vor fi adăugate zerouri înainte de număr. Dacă simbolul de completare nu este specificat explicit, se va utiliza simbolul de completare implicit (spațiu).

#include <iostream>
#include <format>

int main()
{
    int a {2}; 
    int b {5};
    int c {-8};
    std::cout << std::format("a = {:07}", a) << std::endl;
    std::cout << std::format("b = {:7}", b) << std::endl;
    std::cout << std::format("c = {:07}", c) << std::endl;
}

În acest caz, sunt afișate trei numere, pentru fiecare dintre ele stabilindu-se o lungime minimă de 7 caractere. Totuși, pentru primul și al treilea număr se va utiliza simbolul de completare "0", iar pentru al doilea număr se va utiliza simbolul de completare implicit (spațiu). Rezultatul pe consolă va fi:

a = 0000002
b =       5
c = -000008

Dacă numărului i se adaugă un semn (+ sau -), caracterele de completare vor fi inserate după semn.

Alinierea

Parametrul align determină cum este aliniată valoarea formatată: la stânga (<), la dreapta (>) sau la centru (^). Alinierea implicită depinde de tipul valorii.

#include <iostream>
#include <format>

int main()
{
    std::cout << std::format("{:>7}|{:>7}|{:>7}|{:>7}|\n", 1, -.2, 3, 4);
    std::cout << std::format("{:<7}|{:<7}|{:<7}|{:<7}|\n", 1, -.2, 3, 4);
    std::cout << std::format("{:^7}|{:^7}|{:^7}|{:^7}|\n", 1, -.2, 3, 4);
}

Rezultatul pe consolă va fi:

      1|   -0.2|      3|      4|
1      |-0.2   |3      |4      |
   1   | -0.2  |   3   |   4   |

Specificația tipului

Parametrul type stabilește tipul de formatare (nu tipul datelor). Tipul specific va depinde de tipul de date al valorii.

Pentru numerele cu virgulă mobilă, se aplică următoarele tipuri:

  • f: formatare cu punct fix
  • g: formatare generală
  • e: notație științifică
  • a: notație în sistemul hexazecimal

Pentru numerele întregi, se adaugă tipurile:

  • b: afișează numărul în format binar
  • x: afișează numărul în format hexazecimal

Aplicarea tipurilor:

#include <iostream>
#include <format>

int main()
{
    std::cout << std::format("{:f} \n", 34.56);     // 34.560000
    std::cout << std::format("{:g} \n", 34.56);     // 34.56
    std::cout << std::format("{:e} \n", 34.56);     // 3.456000e+01
    std::cout << std::format("{:a} \n", 34.56);     // 1.147ae147ae148p+5
    std::cout << std::format("{:b} \n", 122);       // 1111010
    std::cout << std::format("{:032b} \n", 122);    // 00000000000000000000000001111010
    std::cout << std::format("{:x} \n", 122);       // 7A
}

Suprascrierea ordinii argumentelor

În mod implicit, argumentele sunt transmise șirului de formatare în ordinea în care sunt plasate. Totuși, putem suprascrie această ordine indicând în interiorul acoladelor numărul argumentului înainte de două puncte (numerotarea începe de la 0):

#include <iostream>
#include <format>

int main()
{
    int a{10};
    int b{20};
    int c{30};
    std::cout << std::format("{2:} {1:} {0:}", a, b, c);    // 30 20 10
}

În acest caz, deși în funcția std::format primul argument pentru afișare este numărul a, totuși în șirul de formatare primul va fi afișat al treilea argument {2:}. În mod similar, putem specifica ieșirea pentru alți argumente.

Specificația explicită a indicilor argumentelor poate fi utilă atunci când dorim să afișăm același argument de mai multe ori. De exemplu, să afișăm același număr în formă zecimală, binară și hexazecimală:

#include <iostream>
#include <format>

int main()
{
    int a{10};
    int b{20};
    int c{30};
    std::cout << std::format("{0:} {0:b} {0:X}", 62);    // 62 111110 3E
}

În acest caz, va fi afișat numărul 62 în formă zecimală (62), binară (111110) și hexazecimală (3E).