Convertir la chaîne Elixir en entier ou en flottant

97

J'ai besoin de convertir une chaîne en une valeur à virgule flottante ou un entier. Il n'y avait pas de méthode telle que,

string_to_integer
Lahiru
la source

Réponses:

153

Vérifiez Integer.parse/1et Float.parse/1.

José Valim
la source
36
Notez que cela renverra un tuple (en cas de succès) et non directement l'entier. Si vous voulez faire cela, voir @Szymon Jeż répondre avecString.to_integer/1
6
Y a-t-il une raison d'utiliser Integer.parse/1over String.to_integer/1?
Ian Vaughan
10
@IanVaughan Integer.parse/1renvoie un :erroratome en cas d'échec. String.to_integer/1jette un (FunctionClauseError).
Jonathan Soifer
52

En plus des fonctions Integer.parse/1et Float.parse/1que José a suggérées, vous pouvez également vérifier String.to_integer/1et String.to_float/1.

Conseil: Voir aussi to_atom/1, to_char_list/1, to_existing_atom/1pour d' autres conversions.

Szymon Jeż
la source
27

Merci à tous sur cette page, en simplifiant simplement une réponse ici:

{intVal, ""} = Integer.parse(val)

car il valide que la chaîne entière a été analysée (pas seulement un préfixe).

Roozbeh Zabihollahi
la source
Cela lèvera une erreur si le val n'est pas purement un entier. J'ai ajouté un cas sur le résultat pour m'assurer que la conversion a réussi. La deuxième clause peut être générique pour attraper: erreur ou une deuxième chaîne non vide car vous ne vous souciez pas beaucoup de savoir si l'entrée était "x3" ou "3x".
Sinc le
14

Il y a 4 fonctions pour créer un nombre à partir d'une chaîne

  • String.to_integer, String.to_float
  • Integer.parse, Float.parse

String.to_integerfonctionne bien mais String.to_floatest plus dur:

iex()> "1 2 3 10 100" |> String.split |> Enum.map(&String.to_integer/1)
[1, 2, 3, 10, 100]

iex()> "1.0 1 3 10 100" |> String.split |> Enum.map(&String.to_float/1)
** (ArgumentError) argument error
    :erlang.binary_to_float("1")
    (elixir) lib/enum.ex:1270: Enum."-map/2-lists^map/1-0-"/2
    (elixir) lib/enum.ex:1270: Enum."-map/2-lists^map/1-0-"/2

Comme String.to_floatne peut gérer que des flottants bien formatés, par exemple:, 1.0not 1(entier). Cela a été documenté dans String.to_floatle doc

Renvoie un flottant dont la représentation textuelle est une chaîne.

string doit être la représentation sous forme de chaîne d'un flottant comprenant un point décimal. Afin d'analyser une chaîne sans virgule décimale comme un flottant, alors Float.parse / 1 doit être utilisé. Sinon, une ArgumentError sera déclenchée.

Mais Float.parseretourne un tuple de 2 éléments, pas le nombre que vous voulez, donc le mettre dans le pipeline n'est pas "cool":

iex()> "1.0 1 3 10 100" |> String.split \
|> Enum.map(fn n -> {v, _} = Float.parse(n); v end)

[1.0, 1.0, 3.0, 10.0, 100.0]

Utiliser elempour obtenir le premier élément du tuple le rend plus court et plus doux:

iex()> "1.0 1 3 10 100" |> String.split \
|> Enum.map(fn n -> Float.parse(n) |> elem(0) end)

[1.0, 1.0, 3.0, 10.0, 100.0]
HVNSweeting
la source
11

Vous pouvez le convertir en char_list puis utiliser Erlang to_integer/1ou to_float/1.

Par exemple

iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}

iex> myInt
23
Jonas
la source
Comment l'utiliser dans les fonctions? Ma meilleure solution est fn q -> {v, _} = Float.parse(q); v endque je n'aime pas. J'aime l'utiliser dans Enum.map, par exemple, list |> Enum.map(&String.to_float/1)mais string.to_float ne fonctionne pas pour les nombres entiers?
Zhomart
5
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
kangkyu
la source
1
OMI c'est la meilleure réponse.
Marcin Adamczyk
J'ai eu cette erreur: ** (UndefinedFunctionError) la fonction Decimal.new/1 n'est pas définie (le module Decimal n'est pas disponible)
Daniel Cukier
4

Le problème avec l'utilisation Integer.parse/1est qu'il analysera toute partie non numérique de la chaîne tant qu'elle se trouve à la fin. Par exemple:

Integer.parse("01") # {1, ""}
Integer.parse("01.2") # {1, ".2"}
Integer.parse("0-1") # {0, "-1"}
Integer.parse("-01") # {-1, ""}
Integer.parse("x-01") # :error
Integer.parse("0-1x") # {0, "-1x"}

De même String.to_integer/1a les résultats suivants:

String.to_integer("01") # 1
String.to_integer("01.2") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")
String.to_integer("0-1") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")
String.to_integer("-01") # -1
String.to_integer("x-01") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")
String.to_integer("0-1x") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")

Au lieu de cela, validez d'abord la chaîne.

re = Regex.compile!("^[+-]?[0-9]*\.?[0-9]*$")
Regex.match?(re, "01") # true
Regex.match?(re, "01.2") # true
Regex.match?(re, "0-1") # false
Regex.match?(re, "-01") # true
Regex.match?(re, "x-01") # false
Regex.match?(re, "0-1x") # false

L'expression régulière pourrait être plus simple (par exemple ^[0-9]*$) en fonction de votre cas d'utilisation.

Nibir Bora
la source
0

Si vous vouliez convertir une chaîne en n'importe quel type numérique dans la chaîne et supprimer tous les autres caractères, c'est probablement exagéré, mais retournera un flottant si c'est un flottant ou un int si c'est un int ou nil si la chaîne ne contient pas un type numérique.

@spec string_to_numeric(binary()) :: float() | number() | nil
def string_to_numeric(val) when is_binary(val), do: _string_to_numeric(Regex.replace(~r{[^\d\.]}, val, ""))
defp _string_to_numeric(val) when is_binary(val), do: _string_to_numeric(Integer.parse(val), val)
defp _string_to_numeric(:error, _val), do: nil
defp _string_to_numeric({num, ""}, _val), do: num
defp _string_to_numeric({num, ".0"}, _val), do: num
defp _string_to_numeric({_num, _str}, val), do: elem(Float.parse(val), 0)
jrichocean
la source