web-dev-qa-db-fra.com

Convertir une chaîne Elixir en entier ou en virgule flottante

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
79
Lahiru
129
José Valim

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

Indice: voir aussi to_atom/1, to_char_list/1, to_existing_atom/1pour d'autres conversions.

45
Szymon Jeż

Merci aux gens sur cette page, 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).

22
Roozbeh Zabihollahi

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_integer Fonctionne bien mais String.to_float Est plus difficile:

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_float Ne peut gérer que des fonds flottants bien formatés, par exemple: 1.0, Pas 1 (Entier). Cela a été documenté dans la documentation de String.to_float

Retourne un float dont la représentation textuelle est une chaîne.

string doit être la représentation sous forme de chaîne d'un float incluant un point décimal. Afin d'analyser une chaîne sans virgule décimale en tant que float, il convient d'utiliser Float.parse/1. Sinon, une ArgumentError sera levée.

Mais Float.parse Renvoie un tuple de 2 éléments, pas le nombre que vous voulez, alors le mettre en 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 elem pour obtenir le premier élément de 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]
10
HVNSweeting

Vous pouvez le convertir en une liste de caractères puis utiliser le fichier Erlang to_integer/1 ou to_float/1.

Par exemple.

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

iex> myInt
23
10
Jonas

Le problème avec Integer.parse/1 _ c'est-à-dire qu'il analysera toute partie non numérique de la chaîne tant qu'elle se trouvera à 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/1 a 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 la chaîne en premier.

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.

3
Nibir Bora
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
1
kangkyu

Si vous vouliez convertir une chaîne en un type numérique quelconque et supprimer tous les autres caractères, ceci est probablement excessif, mais vous renverrez un float s'il s'agit d'un float ou un entier si c'est un entier 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)
0
jrichocean