Перетворити рядок еліксиру на ціле чи плаваюче


97

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

string_to_integer

Відповіді:


153

Перевірте Integer.parse/1і Float.parse/1.


36
Зверніть увагу, що це поверне кортеж (у разі успіху), а не ціле число безпосередньо. Якщо ви хочете це зробити, див. Відповідь @Szymon Jeż зString.to_integer/1

6
Чи є якась причина використовувати Integer.parse/1над String.to_integer/1?
Ян Вон

10
@IanVaughan Integer.parse/1повертає :errorатом, якщо не вдалося. String.to_integer/1кидає a (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 не є цілим числом. Я додав випадок на результат, щоб переконатися, що конверсія була успішною. Другий пункт може бути загальним для ловлі: помилка або не порожній другий рядок, оскільки вам не дуже важливо, чи був вхід "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

Як String.to_floatможе обробляти лише добре відформатований float, наприклад:, 1.0not 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]

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

1
ІМО це найкраща відповідь.
Марцін Адамчик

Я отримав цю помилку: ** (UndefinedFunctionError) функція Decimal.new/1 не визначена (модуль Десятковий недоступний)
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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.