Muszę przekonwertować ciąg na wartość zmiennoprzecinkową lub liczbę całkowitą. Nie było takiej metody jak:
string_to_integer
Odpowiedzi:
Sprawdź Integer.parse/1i Float.parse/1.
Integer.parse/1over String.to_integer/1?
Integer.parse/1zwraca :erroratom, jeśli się nie powiedzie. String.to_integer/1rzuca (FunctionClauseError).
Oprócz funkcji Integer.parse/1i, Float.parse/1które zasugerował José, możesz również sprawdzić String.to_integer/1i String.to_float/1.
Wskazówka: Patrz również to_atom/1, to_char_list/1, to_existing_atom/1dla innych konwersji.
Dzięki ludziom na tej stronie, upraszczam odpowiedź tutaj:
{intVal, ""} = Integer.parse(val)
ponieważ sprawdza, czy przeanalizowano cały ciąg (a nie tylko przedrostek).
Istnieją 4 funkcje do tworzenia liczby z łańcucha
String.to_integerdziała ładnie, ale String.to_floatjest twardszy:
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
Jak String.to_floatobsługuje tylko dobrze sformatowaną liczbę zmiennoprzecinkową, np .: 1.0, not 1(integer). To zostało udokumentowane w dokumencie String.to_float's
Zwraca liczbę zmiennoprzecinkową, której reprezentacją tekstową jest łańcuch.
ciąg musi być ciągiem reprezentującym wartość zmiennoprzecinkową, w tym kropką dziesiętną. Aby przeanalizować ciąg bez kropki dziesiętnej jako zmiennoprzecinkowy, należy użyć Float.parse / 1. W przeciwnym razie zostanie zgłoszony ArgumentError.
Ale Float.parsezwraca krotkę z 2 elementów, a nie żądaną liczbę, więc umieszczenie jej w potoku nie jest „fajne”:
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]
Użycie elemdo pobrania pierwszego elementu z krotki sprawi, że będzie on krótszy i słodszy:
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]
Możesz przekonwertować go na char_list, a następnie użyć Erlang to_integer/1lub to_float/1.
Na przykład
iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}
iex> myInt
23
fn q -> {v, _} = Float.parse(q); v endco mi się nie podoba. Lubię go używać Enum.map, np. list |> Enum.map(&String.to_float/1)Ale string.to_float nie działa dla liczb całkowitych?
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
Problem z użyciem Integer.parse/1polega na tym, że sparsuje każdą nieliczbową część łańcucha, o ile znajduje się na końcu. Na przykład:
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"}
Podobnie String.to_integer/1ma następujące wyniki:
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")
Zamiast tego najpierw sprawdź poprawność ciągu.
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
Wyrażenie regularne może być prostsze (np. ^[0-9]*$) W zależności od przypadku użycia.
Jeśli chcesz przekonwertować ciąg na dowolny typ liczbowy w ciągu i usunąć wszystkie inne znaki, prawdopodobnie jest to przesada, ale zwróci wartość typu float, jeśli jest to float lub int, jeśli jest to int lub nil, jeśli łańcuch nie zawiera typ liczbowy.
@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