Respuestas:
Compruebe Integer.parse/1
y Float.parse/1
.
Integer.parse/1
más String.to_integer/1
?
Integer.parse/1
devuelve un :error
átomo si no tiene éxito. String.to_integer/1
lanza un (FunctionClauseError)
.
Además de las funciones Integer.parse/1
y Float.parse/1
que sugirió José, también puede verificar String.to_integer/1
y String.to_float/1
.
Sugerencia: Véase también to_atom/1
, to_char_list/1
, to_existing_atom/1
para otras conversiones.
Gracias a la gente de esta página, simplemente simplificando una respuesta aquí:
{intVal, ""} = Integer.parse(val)
ya que valida que se analizó toda la cadena (no solo un prefijo).
Hay 4 funciones para crear un número a partir de una cadena
String.to_integer
funciona bien pero String.to_float
es más difícil:
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
Como String.to_float
solo puede manejar un flotante bien formateado, por ejemplo:, 1.0
no 1
(entero). Eso fue documentado en String.to_float
el documento de
Devuelve un flotante cuya representación de texto es una cadena.
cadena debe ser la representación de cadena de un flotante que incluya un punto decimal. Para analizar una cadena sin punto decimal como flotante, se debe usar Float.parse / 1. De lo contrario, se generará un ArgumentError.
Pero Float.parse
devuelve una tupla de 2 elementos, no el número que desea, por lo que ponerlo en canalización no es "genial":
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]
Usar elem
para obtener el primer elemento de la tupla lo hace más corto y dulce:
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]
Puede convertirlo a char_list y luego usar Erlang to_integer/1
o to_float/1
.
P.ej
iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}
iex> myInt
23
fn q -> {v, _} = Float.parse(q); v end
que no me gusta. Me gusta usarlo Enum.map
, por ejemplo, list |> Enum.map(&String.to_float/1)
pero ¿string.to_float no funciona para números enteros?
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
El problema con el uso Integer.parse/1
es que analizará cualquier parte no numérica de la cadena siempre que esté al final. Por ejemplo:
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"}
Del mismo modo String.to_integer/1
tiene los siguientes resultados:
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")
En su lugar, valide la cadena primero.
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
La expresión regular podría ser más simple (por ejemplo ^[0-9]*$
) dependiendo de su caso de uso.
Si desea convertir una cadena a cualquier tipo numérico que esté dentro de la cadena y eliminar todos los demás caracteres, esto probablemente sea excesivo, pero devolverá un flotante si es un flotante o un int si es un int o nil si la cadena no contiene un tipo numérico.
@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