Преобразование строки Эликсира в целое число или число с плавающей запятой

97

Мне нужно преобразовать строку в значение с плавающей запятой или целое число. Не было такого метода, как,

string_to_integer
Лахиру
источник

Ответы:

153

Проверить Integer.parse/1и Float.parse/1.

Хосе Валим
источник
36
Обратите внимание, что это вернет кортеж (в случае успеха), а не целое число напрямую. Если вы хотите это сделать, посмотрите ответ @Szymon JeżString.to_integer/1
6
Есть ли причина использовать Integer.parse/1over String.to_integer/1?
Ян Воган
10
@IanVaughan Integer.parse/1возвращает :errorатом в случае неудачи . String.to_integer/1бросает (FunctionClauseError).
Джонатан Сойфер
52

В дополнении к Integer.parse/1и Float.parse/1функциям , которые Хосе предложенных вы можете также проверить String.to_integer/1и String.to_float/1.

Подсказка: Смотрите также to_atom/1, to_char_list/1, to_existing_atom/1для других преобразований.

Шимон Джео
источник
27

Спасибо, ребята на этой странице, просто упрощаю ответ здесь:

{intVal, ""} = Integer.parse(val)

поскольку он подтверждает, что была проанализирована вся строка (а не только префикс).

Рузбех Забихоллахи
источник
Это вызовет ошибку, если val не является целым числом. Я добавил к результату случай, чтобы убедиться, что преобразование прошло успешно. Второе предложение может быть общим для catch: error или непустой второй строки, поскольку вам не важно, было ли введено «x3» или «3x».
Sinc,
14

Есть 4 функции для создания числа из строки

  • String.to_integer, String.to_float
  • Integer.parse, Float.parse

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

As String.to_floatможет обрабатывать только хорошо отформатированные числа с плавающей запятой, например:, 1.0not 1(целое число). Это было задокументировано в String.to_floatдокументации пользователя

Возвращает число с плавающей запятой, текстовое представление которого является строкой.

строка должна быть строковым представлением числа с плавающей запятой, включая десятичную точку. Для синтаксического анализа строки без десятичной точки как числа с плавающей запятой следует использовать Float.parse / 1. В противном случае возникнет ошибка ArgumentError.

Но Float.parseвозвращает кортеж из двух элементов, а не то число, которое вы хотите, поэтому помещать его в конвейер не "круто":

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]
HVNSweeting
источник
11

Вы можете преобразовать его в 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 не работает для целых чисел?
Жомарт
5
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
Kangkyu
источник
1
ИМО, это лучший ответ.
Marcin Adamczyk
Я получил эту ошибку: ** (UndefinedFunctionError) функция Decimal.new/1 не определена (модуль Decimal недоступен)
Daniel Cukier
4

Проблема с использованием 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]*$) в зависимости от вашего варианта использования.

Нибир Бора
источник
0

Если вы хотите преобразовать строку в любой числовой тип внутри строки и удалить все другие символы, это, вероятно, излишне, но вернет 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)
Jrichocean
источник