Șiruri de caractere

Conversie din text în număr cu validare, în C++

Construiește un întreg din cifre și verifică semnul, caracterele și limita înaintea înmulțirii. Exemple complete cu char[] și std::string.

Textul -120 poate reprezenta numărul -120, dar 12a, + și o linie goală nu sunt numere în formatul ales. Conversia corectă nu înseamnă numai acumularea cifrelor: verificăm și dacă textul respectă formatul și dacă valoarea încape în domeniul acceptat.

Contractul parserului

Un parser este o procedură care interpretează textul după reguli precise. Aici citim o linie de cel mult 1000 de caractere obișnuite, fără diacritice. Acceptăm un semn opțional + sau -, urmat de cel puțin o cifră. Nu acceptăm spații, punct zecimal sau alte caractere. Domeniul numeric este [-10^9,10^9].

Zerourile inițiale sunt permise: 0007 produce 7. Textul -0 produce 0. Pentru orice format invalid sau depășire de domeniu, afișăm INVALID. Aceste alegeri sunt convenții ale problemei, nu reguli obligatorii pentru orice aplicație.

Verificăm înainte să construim următoarea cifră

După citirea unui eventual semn, trebuie să mai existe cel puțin un caracter. Pentru fiecare cifră c, noua valoare ar fi valoare·10+c. Ea este cel mult limita L exact când valoare≤(L-c)/10, pentru valorile nenegative folosite aici.

Aplicăm această comparație înainte de înmulțire. Dacă am verifica abia după calcul, o depășire a tipului ar fi avut deja loc pentru limite mai mari. În această problemă, valoarea parțială acceptată nu depășește 10^9.

Pentru textul 204, valorile intermediare sunt 2,20,204. Înainte de fiecare actualizare verificăm cifra și limita numerică.Pentru textul 204, valorile intermediare sunt 2,20,204. Înainte de fiecare actualizare verificăm cifra și limita numerică.Mărește schema ↗

Varianta cu char[]

#include <iostream>
#include <cstring>
using namespace std;
int main() {
    char s[1001]; cin.getline(s,1001);
    int n=static_cast<int>(strlen(s)),i=0,semn=1;
    if(i<n && (s[i]=='+' || s[i]=='-')) { if(s[i]=='-') semn=-1; ++i; }
    bool valid=i<n; long long valoare=0;
    for(;i<n && valid;++i) {
        if(s[i]<'0' || s[i]>'9') { valid=false; break; }
        int cifra=s[i]-'0';
        if(valoare>(1000000000LL-cifra)/10) { valid=false; break; }
        valoare=valoare*10+cifra;
    }
    if(valid) cout << semn*valoare << '\n'; else cout << "INVALID\n";
}

Varianta echivalentă cu std::string

Păstrăm aceleași limite și exemple. Șirul clasic rezervă spațiu inclusiv pentru terminatorul nul; obiectul string își gestionează memoria. Indicii caracterelor utile pornesc de la zero în ambele variante.

#include <string>

#include <iostream>

using namespace std;
int main() {
    string s; getline(cin,s);
    int n=static_cast<int>(s.size()),i=0,semn=1;
    if(i<n && (s[i]=='+' || s[i]=='-')) { if(s[i]=='-') semn=-1; ++i; }
    bool valid=i<n; long long valoare=0;
    for(;i<n && valid;++i) {
        if(s[i]<'0' || s[i]>'9') { valid=false; break; }
        int cifra=s[i]-'0';
        if(valoare>(1000000000LL-cifra)/10) { valid=false; break; }
        valoare=valoare*10+cifra;
    }
    if(valid) cout << semn*valoare << '\n'; else cout << "INVALID\n";
}

Cifra și codul caracterului sunt lucruri diferite

Caracterul '7' nu are valoarea numerică 7. După ce verificăm că este între '0' și '9', scăderea lui '0' produce cifra corespunzătoare. Verificarea trebuie să preceadă folosirea rezultatului, altfel o literă ar participa la calcul ca și cum ar fi cifră.

În șirul clasic, capacitatea 1001 lasă loc pentru terminatorul nul după cel mult 1000 de caractere utile. Varianta string gestionează stocarea, dar nu elimină nevoia verificării formatului. Ambele parcurg caracterele de la indicele zero.

Timpul este O(L), unde L este lungimea liniei, iar memoria suplimentară față de text este O(1). La prima eroare putem opri analiza deoarece întregul rezultat este deja invalid. Nu returnăm un prefix numeric valid dintr-un text invalid.

Exersează

-120, +7, 0007 și -0 produc -120,7,7,0. 12a, +, textul gol și 1000000001 sunt invalide. Testează separat ambele limite, -1000000000 și 1000000000, care trebuie acceptate.

Revezi caracterele și cifrele, citirea liniilor și tipurile numerice.

Întrebări frecvente

Ce trebuie verificat la conversia unui text în număr?

Verifică formatul complet, existența cel puțin a unei cifre și încadrarea în domeniul numeric. În lecție sunt acceptate un semn opțional și cifre, fără spații sau alte caractere.

Este textul format doar din semnul plus un număr valid?

Nu. După semnul opțional trebuie să existe cel puțin o cifră. Șirurile +, - și textul gol sunt respinse de formatul declarat.

De ce verific limita înainte de înmulțirea cu 10?

Acumularea unei cifre folosește valoarea precedentă înmulțită cu 10, apoi adună cifra. Dacă aceste operații depășesc tipul, verificarea făcută doar după calcul este prea târzie.

Un pas mai departe

Autentifică-te pentru a păstra progresul în cont.

Exersează cu o problemă →