C# Texto → Número
Tudo o que o usuário digita chega ao programa como texto. Mesmo que ele digite 29, o programa recebe a string "29", e com uma string não dá para fazer contas. O mesmo vale para números que vêm de um arquivo ou de um site. Nesta aula você vai aprender a transformar texto em número com Parse, ver as exceções que aparecem quando o texto não é um número, descobrir por que "3.5" vira 35 num computador em português, e usar o TryParse, o jeito seguro de ler números do teclado.
- Por que
"29" + 1dá"291", e como converter comint.Parse,double.Parseedecimal.Parse. - As exceções do
Parse:FormatException,OverflowExceptioneArgumentNullException. - A cultura: por que
double.Parse("3.5")dá35no Ubuntu em português, e oCultureInfo.InvariantCulture. - O
TryParsecomout: converter sem o programa parar. - Ler um número do teclado com
Console.ReadLine+TryParse. bool.Parse,char.Parsee oConvert.ToInt32.
Todos os programas desta aula foram rodados com o .NET 10 (C# 14) na máquina fictícia da Ana (usuária ana, computador notebook, Ubuntu em português do Brasil), na pasta ~/cs, com dotnet run arquivo.cs.
A ideia: o número escrito no papel
Alguém deixa um bilhete para a Ana: "comprei 29 laranjas". O bilhete tem os desenhos 2 e 9, mas para somar com as laranjas que ela já tem, ela precisa ler o bilhete e entender que ali está o número vinte e nove.
No C#, a string "29" é o bilhete: dois caracteres, '2' e '9'. O int 29 é o número. "Ler o bilhete" se chama parse (em inglês, "analisar"): olhar o texto, conferir se ele forma um número e calcular esse número.
1. Parse: de texto para número
string texto = "29";
int idade = int.Parse(texto);
Console.WriteLine(idade + 1);
Console.WriteLine(texto + 1);
double altura = double.Parse("1,65");
decimal preco = decimal.Parse("19,90");
long grande = long.Parse("8100000000");
Console.WriteLine(altura * 2);
Console.WriteLine(preco * 2);
Console.WriteLine(grande);
$ dotnet run parse1.cs 30 « o número 29, mais 1 291 « o texto "29", com "1" grudado 3,3 39,80 8100000000
- int.Parse(texto)
- "Analise este texto como
int". Recebe a string"29"e devolve oint29. Cada tipo de número tem o seu:int.Parse,long.Parse,double.Parse,decimal.Parse… - idade + 1 → 30 · texto + 1 → 291
- A diferença entre o número e o texto: o
+soma números, mas junta textos (aula Operadores Aritméticos). - double.Parse("1,65") · decimal.Parse("19,90")
- Com vírgula! O
Parselê o texto do jeito do país do computador, e no Brasil a vírgula separa os decimais. A seção 3 explica isso com calma.
Você já viu na aula Conversão de Tipos que o cast não funciona aqui: (int)"29" nem compila (CS0030). Texto e número são coisas diferentes demais; é preciso analisar o texto, e quem faz isso é o Parse.
O que o Parse aceita
Console.WriteLine(int.Parse(" 42 "));
Console.WriteLine(int.Parse("-7"));
Console.WriteLine(int.Parse("+7"));
Console.WriteLine(int.Parse("007"));
$ dotnet run parseespaco.cs 42 -7 7 7
Espaços no começo e no fim são ignorados, o sinal (- ou +) é aceito, e zeros à esquerda não atrapalham. Qualquer outra coisa, não.
2. Quando o texto não é um número
Se o texto não forma um número, o Parse não tem o que devolver. Ele lança uma exceção, e o programa para:
int idade = int.Parse("vinte");
Console.WriteLine(idade);
$ dotnet run parseerro1.cs Unhandled exception. System.FormatException: The input string 'vinte' was not in a correct format. at System.Number.ThrowFormatException[TChar](ReadOnlySpan`1 value) at System.Int32.Parse(String s) at Program.<Main>$(String[] args) in /home/ana/cs/parseerro1.cs:line 1
- System.FormatException
- "Exceção de formato": o texto não está no formato de um número.
- The input string 'vinte' was not in a correct format.
- "O texto de entrada 'vinte' não estava num formato correto." A mensagem mostra o texto que veio, o que ajuda muito a achar o problema.
- at System.Number.ThrowFormatException… · at System.Int32.Parse(String s)
- As linhas de dentro do .NET: o erro nasceu dentro do
int.Parse(lembre:Int32é o nome .NET doint). - at Program.<Main>$ … parseerro1.cs:line 1
- A linha que interessa: o seu código, linha 1. O código de saída é 134.
Há três exceções possíveis:
| Chamada | Exceção | Mensagem |
|---|---|---|
int.Parse("vinte") | FormatException | The input string 'vinte' was not in a correct format. |
int.Parse("29.5") | FormatException | The input string '29.5' was not in a correct format. (um int não tem vírgula) |
int.Parse("") | FormatException | The input string '' was not in a correct format. (o usuário só apertou Enter) |
int.Parse("1.000") | FormatException | The input string '1.000' was not in a correct format. (separador de milhar não vale no int) |
int.Parse("8100000000") | OverflowException | Value was either too large or too small for an Int32. (é um número, mas não cabe no int) |
int.Parse(null) | ArgumentNullException | Value cannot be null. (Parameter 's') (não há texto nenhum) |
Todas essas mensagens saíram do laboratório. Exceções saem sempre em inglês, mesmo no Ubuntu em português. Elas têm um capítulo inteiro, a partir de Exceções; por enquanto, o importante é: com texto que vem de fora (do teclado, de um arquivo), o Parse pode parar o seu programa. A seção 4 mostra como evitar.
3. A cultura: por que "3.5" vira 35
Agora a pegadinha mais famosa do C# no Brasil. No código, números com vírgula se escrevem com ponto (3.5). Mas o Parse lê o texto do jeito do país do computador. Veja no Ubuntu da Ana, que está em português:
double a = double.Parse("3,5");
double b = double.Parse("3.5");
double c = double.Parse("1.234,5");
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
$ dotnet run cultura1.cs 3,5 35 « "3.5" virou trinta e cinco! 1234,5
No Brasil, a vírgula separa os decimais e o ponto separa os milhares (1.234,5). Então, para o double.Parse em pt-BR, o ponto de "3.5" é um separador de milhar, e separadores de milhar são simplesmente ignorados: sobra 35. Nenhuma exceção, nenhum aviso: só um número dez vezes maior. Com dinheiro é pior:
decimal p = decimal.Parse("19.90");
Console.WriteLine(p);
decimal q = decimal.Parse("19,90");
Console.WriteLine(q);
$ dotnet run cultura3.cs 1990 « R$ 19,90 virou R$ 1.990! 19,90
Num computador configurado em inglês (en-US), seria o contrário: "19.90" daria 19,90 e "19,90" daria 1990. O mesmo programa dá resultados diferentes dependendo de onde roda. A configuração de país, idioma e formatos se chama cultura (culture), e a desta máquina é pt-BR.
A solução: dizer qual cultura o texto usa
Quando o texto vem de um lugar com formato fixo (um arquivo CSV, um site, uma API, outro programa), quase sempre ele usa o ponto, como o código. Para esses casos existe a cultura invariante, CultureInfo.InvariantCulture, que é sempre igual em qualquer computador: ponto para decimais, sem separador de milhar.
using System.Globalization;
double b = double.Parse("3.5", CultureInfo.InvariantCulture);
Console.WriteLine(b);
decimal p = decimal.Parse("19.90", CultureInfo.InvariantCulture);
Console.WriteLine(p);
Console.WriteLine(CultureInfo.CurrentCulture.Name);
$ dotnet run cultura2.cs 3,5 19,90 pt-BR
- using System.Globalization;
- "Globalização": a parte do .NET que cuida de culturas. O
usingdeixa você escreverCultureInfosem o nome completo (aula Namespaces e using). - double.Parse("3.5", CultureInfo.InvariantCulture)
- O segundo valor dentro dos parênteses diz: "leia este texto no formato invariante". Agora
"3.5"é três e meio. - 3,5 · 19,90
- Na saída, o
Console.WriteLinecontinua usando a cultura do computador, por isso a vírgula. Ler e mostrar são coisas separadas. - CultureInfo.CurrentCulture.Name
- A cultura atual:
pt-BR.
| De onde vem o texto | Como ler |
|---|---|
| Digitado pelo usuário brasileiro | double.Parse(texto) (cultura do computador: 3,5) |
| Arquivo CSV, JSON, site, API, outro programa | double.Parse(texto, CultureInfo.InvariantCulture) (3.5) |
A aula Cultura (pt-BR × en-US) mostra o assunto inteiro: como mostrar números em outra cultura, datas, moedas e como trocar a cultura do programa.
Missão: o preço da bala veio de um site estrangeiro como "3.50", e o programa mostra Preço: 350. Passe CultureInfo.InvariantCulture como segundo valor do decimal.Parse para mostrar Preço: 3,50.
using System.Globalization;
string doSite = "3.50";
decimal preco = decimal.Parse(doSite);
Console.WriteLine($"Preço: {preco}");
using System.Globalization;
string doSite = "3.50";
decimal preco = decimal.Parse(doSite, CultureInfo.InvariantCulture);
Console.WriteLine($"Preço: {preco}");
4. TryParse: tentar sem quebrar
O Parse é ótimo quando você tem certeza de que o texto é um número. Quando o texto vem de uma pessoa, não há certeza nenhuma: ela pode digitar "vinte", "29 anos" ou só apertar Enter. Para isso existe o TryParse ("tentar analisar"), que nunca lança exceção. Ele responde duas coisas: se deu certo e qual é o número.
string texto = "29";
if (int.TryParse(texto, out int idade))
{
Console.WriteLine($"Idade: {idade}");
}
else
{
Console.WriteLine("Isso não é um número.");
}
string ruim = "vinte";
bool deuCerto = int.TryParse(ruim, out int outro);
Console.WriteLine(deuCerto);
Console.WriteLine(outro);
$ dotnet run tryparse1.cs Idade: 29 False 0
- int.TryParse(texto, out int idade)
- Tenta converter
texto. Devolve umbool:truese deu certo,falsese não. E o número vai para a variável depois doout. - out int idade
out("saída") cria a variávelidadeali mesmo e deixa oTryParseguardar o número nela. É um segundo "resultado" do método, além dobool. Os detalhes dooutestão em ref, out e in.- if ( … ) { … } else { … }
- O
if("se") roda o primeiro bloco quando oboolétrue; oelse("senão") roda o segundo quando éfalse. Por enquanto, leia assim: "se conseguir converter, mostre a idade; senão, avise". Oiftem aula própria: if e else. - deuCerto → False · outro → 0
- Com
"vinte", oTryParsedevolvefalse, e a variável dooutfica com0. O programa não parou.
Você também pode escrever out var idade: o tipo vem do TryParse que você chamou (aula Inferência com var). E o TryParse aceita a cultura, como o Parse: double.TryParse(texto, CultureInfo.InvariantCulture, out double valor).
TryParse
Use Parse só com texto que você controla (que o seu próprio programa gerou). Para o que vem do teclado, de arquivos ou da internet, use TryParse e diga ao usuário o que deu errado.
5. Lendo um número do teclado
Console.ReadLine() ("ler linha") espera o usuário digitar e apertar Enter, e devolve o texto digitado (aula Ler do Teclado). Junto com o TryParse, você tem o jeito certo de pedir um número:
Console.Write("Quantos cadernos? ");
string? texto = Console.ReadLine();
if (int.TryParse(texto, out int quantidade))
{
decimal total = quantidade * 4.50m;
Console.WriteLine($"Total: R$ {total}");
}
else
{
Console.WriteLine($"\"{texto}\" não é um número inteiro.");
}
Rodando três vezes, digitando 3, depois três, depois 12 com espaços em volta:
$ dotnet run readline1.cs Quantos cadernos? 3 Total: R$ 13,50 $ dotnet run readline1.cs Quantos cadernos? três "três" não é um número inteiro. $ dotnet run readline1.cs Quantos cadernos? 12 Total: R$ 54,00
- string? texto = Console.ReadLine();
- O
?depois destringavisa que o texto pode sernull: oReadLinedevolvenullquando não há mais entrada (aula Referências Anuláveis). OTryParseaceitanullsem problema: devolvefalse. - \"{texto}\"
\"põe uma aspa dentro do texto (aula Escapes).
O mesmo com Parse: aviso e exceção
Console.Write("Sua idade: ");
int idade = int.Parse(Console.ReadLine());
Console.WriteLine($"Ano que vem: {idade + 1}");
$ dotnet run readlineparse.cs /home/ana/cs/readlineparse.cs(2,23): warning CS8604: Possível argumento de referência nula para o parâmetro 's' em 'int int.Parse(string s)'. Sua idade: vinte Unhandled exception. System.FormatException: The input string 'vinte' was not in a correct format. at System.Number.ThrowFormatException[TChar](ReadOnlySpan`1 value) at System.Int32.Parse(String s) at Program.<Main>$(String[] args) in /home/ana/cs/readlineparse.cs:line 2
Dois problemas. Antes de rodar, o compilador já avisa (CS8604): o ReadLine pode devolver null, e o int.Parse não aceita null (aconteceria um ArgumentNullException). Depois, quando a Ana digita vinte, o programa para com FormatException. Com TryParse, os dois problemas somem.
6. Outros tipos e o Convert
Console.WriteLine(bool.Parse("true"));
Console.WriteLine(bool.Parse(" False "));
Console.WriteLine(bool.TryParse("sim", out bool b));
Console.WriteLine(char.Parse("A"));
Console.WriteLine(double.Parse("1e3"));
Console.WriteLine(decimal.TryParse("R$ 10,00", out decimal d));
Console.WriteLine(int.TryParse("12abc", out int i));
$ dotnet run outros.cs True False False A 1000 False False
- bool.Parse("true") · bool.Parse(" False ")
- Aceita
trueefalse, com maiúsculas ou minúsculas e espaços em volta. Só em inglês:"sim"dáfalsenoTryParse(eFormatException: String 'sim' was not recognized as a valid Boolean.noParse). - char.Parse("A")
- Uma string de exatamente um caractere vira
char. - double.Parse("1e3")
- A notação científica é aceita: 1000.
- "R$ 10,00" · "12abc"
- Símbolos e letras no meio fazem o
TryParsedevolverfalse. (Para ler moeda, existedecimal.Parse(texto, NumberStyles.Currency), que aceita"R$ 1.234,50".)
Convert.ToInt32
A classe Convert (aula Conversão de Tipos) também converte texto: Convert.ToInt32("29") é o mesmo que int.Parse("29"), com as mesmas exceções. A única diferença: com null, o Convert.ToInt32 devolve 0 em vez de lançar ArgumentNullException. Isso parece cômodo, mas esconde o problema ("o usuário digitou zero ou não digitou nada?"). Prefira TryParse.
| Situação | Use |
|---|---|
| Texto que veio do usuário, de um arquivo, da internet | int.TryParse(texto, out int n) |
| Texto que com certeza é um número (o seu programa gerou) | int.Parse(texto) |
| Texto com ponto decimal, de arquivo ou API | double.Parse(texto, CultureInfo.InvariantCulture) |
| Dinheiro digitado | decimal.TryParse(texto, out decimal valor) |
| Sim/não em texto | bool.TryParse (só true/false) |
Quando dá errado
System.FormatException: The input string '…' was not in a correct format.
O que significa: o texto não é um número do tipo pedido: tem letras, está vazio, tem vírgula num int, ou separador de milhar ("1.000") num int. A mensagem mostra o texto entre aspas simples.
Como consertar: use TryParse e trate o false. Se o texto devia ser válido, olhe o que está entre as aspas da mensagem: muitas vezes há um espaço ou um caractere a mais.
System.OverflowException: Value was either too large or too small for an Int32.
O que significa: o texto é um número, mas não cabe no tipo ("8100000000" num int).
Como consertar: use um tipo maior (long.Parse). O TryParse também devolve false nesse caso.
System.ArgumentNullException: Value cannot be null. (Parameter 's')
O que significa: o Parse recebeu null, por exemplo de um Console.ReadLine() quando a entrada acabou.
Como consertar: TryParse, que aceita null e devolve false.
warning CS8604: Possível argumento de referência nula para o parâmetro 's' em 'int int.Parse(string s)'.
O que significa: o compilador viu que o valor passado ao Parse pode ser null (o retorno do ReadLine é string?). É um aviso: o programa roda, mas pode parar com ArgumentNullException.
Como consertar: troque por TryParse. (Aula Avisos do Compilador.)
"3.5" → 35, "19.90" → 1990)
O que significa: um texto com ponto decimal foi lido na cultura pt-BR, em que o ponto separa milhares. Não há exceção nem aviso.
Como consertar: se o texto vem de arquivo, site ou outro programa, leia com CultureInfo.InvariantCulture. Se vem de um usuário brasileiro, peça a vírgula. Veja Cultura.
error CS0030: Não é possível converter tipo "string" em "int"
O que significa: você tentou (int)texto. Cast não converte texto.
Como consertar: int.Parse(texto) ou int.TryParse(texto, out int n).
Referência rápida
| Escrita | O que faz |
|---|---|
int.Parse(texto) | Converte ou lança FormatException / OverflowException / ArgumentNullException |
long.Parse, double.Parse, decimal.Parse, bool.Parse, char.Parse | O mesmo para cada tipo |
int.TryParse(texto, out int n) | Devolve true/false; o número vai para n (0 se falhou) |
double.Parse(texto, CultureInfo.InvariantCulture) | Lê com ponto decimal, em qualquer computador |
double.TryParse(texto, CultureInfo.InvariantCulture, out double d) | TryParse com cultura |
decimal.Parse(texto, NumberStyles.Currency) | Aceita símbolo de moeda e milhar ("R$ 1.234,50") |
Convert.ToInt32(texto) | Como int.Parse, mas null vira 0 |
numero.ToString() | O caminho contrário: número para texto |
Exercícios
1. O método
Complete para converter o texto em int:
2. A palavra do TryParse
Complete a chamada:
3. A cultura
No Ubuntu da Ana (pt-BR), quanto vale double.Parse("2.5")?
4. O que int.Parse("12,5") faz?
5. int.TryParse("abc", out int n) devolve o quê, e quanto vale n?
6. Um arquivo CSV de um sistema americano tem o valor "1250.75". Como ler em decimal num computador em pt-BR?
7. Por que usar TryParse com o que o usuário digita?
Missão final: o pedido que não quebra
Missão: o caixa pergunta quantos cadernos a cliente quer, e ela digitou doze (por extenso). Com int.Parse, o programa para com FormatException. Reescreva usando int.TryParse, como no exemplo da seção 5: se der certo, mostre o total; senão, mostre Quantidade inválida: doze (o texto digitado), e o programa termina normalmente.
Console.Write("Quantos cadernos? ");
string? texto = Console.ReadLine();
int quantidade = int.Parse(texto);
Console.WriteLine($"Total: R$ {quantidade * 4.50m}");
Console.Write("Quantos cadernos? ");
string? texto = Console.ReadLine();
if (int.TryParse(texto, out int quantidade))
{
Console.WriteLine($"Total: R$ {quantidade * 4.50m}");
}
else
{
Console.WriteLine($"Quantidade inválida: {texto}");
}
A caixa já entrega doze como se a cliente tivesse digitado. Depois de cumprir a missão, troque o programa para receber um número de verdade e veja o total aparecer.
Resumo
- Texto não é número:
"29" + 1é"291". Para converter,int.Parse,double.Parse,decimal.Parse… (o cast não serve:CS0030). - Quando o texto não é um número válido, o
ParselançaFormatException; se não cabe,OverflowException; se énull,ArgumentNullException. - O
Parseusa a cultura do computador. Em pt-BR,double.Parse("3.5")dá 35 edecimal.Parse("19.90")dá 1990, sem erro. Para textos com ponto (arquivos, sites), useCultureInfo.InvariantCulture. int.TryParse(texto, out int n)devolvetrue/falsee nunca lança exceção. Use-o sempre com o que o usuário digita.Console.ReadLine()devolvestring?; oTryParseaceitanull, oParsenão (avisoCS8604).