Réponses:
Vérifiez Integer.parse/1
et Float.parse/1
.
Integer.parse/1
over String.to_integer/1
?
Integer.parse/1
renvoie un :error
atome en cas d'échec. String.to_integer/1
jette un (FunctionClauseError)
.
En plus des fonctions Integer.parse/1
et Float.parse/1
que José a suggérées, vous pouvez également vérifier String.to_integer/1
et String.to_float/1
.
Conseil: Voir aussi to_atom/1
, to_char_list/1
, to_existing_atom/1
pour d' autres conversions.
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).
Il y a 4 fonctions pour créer un nombre à partir d'une chaîne
String.to_integer
fonctionne bien mais String.to_float
est 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_float
ne peut gérer que des flottants bien formatés, par exemple:, 1.0
not 1
(entier). Cela a été documenté dans String.to_float
le 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.parse
retourne 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 elem
pour 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]
Vous pouvez le convertir en char_list puis utiliser Erlang to_integer/1
ou to_float/1
.
Par exemple
iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}
iex> myInt
23
fn q -> {v, _} = Float.parse(q); v end
que 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?
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
Le problème avec l'utilisation Integer.parse/1
est 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/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 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.
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)
String.to_integer/1