Відповіді:
Перевірте Integer.parse/1
і Float.parse/1
.
Integer.parse/1
над String.to_integer/1
?
Integer.parse/1
повертає :error
атом, якщо не вдалося. String.to_integer/1
кидає a (FunctionClauseError)
.
Дякую людям на цій сторінці, просто спростивши відповідь тут:
{intVal, ""} = Integer.parse(val)
оскільки перевіряє, що проаналізовано весь рядок (а не лише префікс).
Є 4 функції для створення числа із рядка
String.to_integer
працює добре, але String.to_float
жорсткіше:
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
Як String.to_float
може обробляти лише добре відформатований float, наприклад:, 1.0
not 1
(ціле число). Це було задокументовано в String.to_float
російському документі
Повертає поплавок, текст якого представляє рядок.
рядок повинен бути поданням рядка з плаваючою точкою, включаючи десяткову крапку. Для того, щоб проаналізувати рядок без десяткової коми як плаваючу, слід використовувати Float.parse / 1. В іншому випадку буде викликано ArgumentError.
Але Float.parse
повертає кортеж із 2-х елементів, а не потрібного вам числа, тому вводити його в конвеєр не "круто":
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]
Використовуючи elem
для отримання першого елемента з кортежу, робіть його коротшим і солодшим:
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]
Ви можете перетворити його на char_list, а потім використовувати Erlang to_integer/1
або to_float/1
.
Напр
iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}
iex> myInt
23
fn q -> {v, _} = Float.parse(q); v end
що мені не подобається. Мені подобається використовувати його в Enum.map
, наприклад, list |> Enum.map(&String.to_float/1)
але string.to_float не працює для цілих чисел?
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
Проблема використання Integer.parse/1
полягає в тому, що буде проаналізовано будь-яку нечислову частину рядка, поки вона знаходиться в кінці. Наприклад:
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"}
Аналогічно String.to_integer/1
має такі результати:
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")
Замість цього спочатку підтвердіть рядок.
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
Регулярний вираз може бути простішим (наприклад ^[0-9]*$
) залежно від вашого випадку використання.
Якщо ви хочете перетворити рядок на будь-який числовий тип, що знаходиться всередині рядка, і видалити всі інші символи, це, мабуть, надмірно, але поверне float, якщо це float, або int, якщо це int або nil, якщо рядок не містить числовий тип.
@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