Ubah string Elixir menjadi integer atau float

97

Saya perlu mengubah string menjadi nilai floating point atau integer. Tidak ada metode seperti,

string_to_integer
Lahiru
sumber

Jawaban:

153

Periksa Integer.parse/1dan Float.parse/1.

José Valim
sumber
36
Perhatikan bahwa ini akan mengembalikan tupel (jika berhasil) dan bukan integer secara langsung. Jika Anda ingin melakukan itu, lihat jawaban @Szymon Jeż denganString.to_integer/1
6
Apakah ada alasan untuk menggunakan Integer.parse/1lebih dari itu String.to_integer/1?
Ian Vaughan
10
@IanVaughan Integer.parse/1mengembalikan :erroratom jika tidak berhasil. String.to_integer/1melempar a (FunctionClauseError).
Jonathan Soifer
52

Selain fungsi Integer.parse/1dan Float.parse/1yang disarankan José, Anda juga dapat memeriksa String.to_integer/1dan String.to_float/1.

Petunjuk: Lihat juga to_atom/1, to_char_list/1, to_existing_atom/1untuk konversi lainnya.

Szymon Jeż
sumber
27

Terima kasih teman-teman di halaman ini, hanya menyederhanakan jawaban di sini:

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

karena memvalidasi bahwa seluruh string telah diurai (bukan hanya awalan).

Roozbeh Zabihollahi
sumber
Ini akan menimbulkan kesalahan jika val tidak murni bilangan bulat. Saya menambahkan kasus pada hasil untuk memastikan konversi berhasil. Klausa kedua bisa umum untuk menangkap: error atau string kedua yang tidak kosong karena Anda tidak terlalu peduli apakah inputnya adalah "x3" atau "3x".
Sinc
14

Ada 4 fungsi untuk membuat angka dari string

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

String.to_integerbekerja dengan baik tetapi String.to_floatlebih sulit:

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

Karena String.to_floathanya dapat menangani float yang diformat dengan baik, misalnya:, 1.0bukan 1(integer). Itu didokumentasikan di String.to_floatdoc

Mengembalikan float yang representasi teksnya adalah string.

string harus merupakan representasi string dari pelampung termasuk titik desimal. Untuk mengurai string tanpa koma desimal sebagai float maka Float.parse / 1 harus digunakan. Jika tidak, ArgumentError akan dimunculkan.

Tetapi Float.parsemengembalikan tupel dari 2 elemen, bukan angka yang Anda inginkan, jadi memasukkannya ke dalam pipeline tidak "keren":

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]

Menggunakan elemuntuk mendapatkan elemen pertama dari tuple membuatnya lebih pendek dan lebih manis:

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
sumber
11

Anda dapat mengubahnya menjadi char_list dan kemudian menggunakan Erlang to_integer/1atau to_float/1.

Misalnya

iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}

iex> myInt
23
Jonas
sumber
Bagaimana cara menggunakannya dalam fungsi? Solusi terbaik saya adalah fn q -> {v, _} = Float.parse(q); v endyang tidak saya sukai. Saya suka menggunakannya di Enum.map, misalnya list |> Enum.map(&String.to_float/1)tetapi string.to_float tidak berfungsi untuk bilangan bulat?
Zhomart
5
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
kangkyu
sumber
1
IMO ini adalah jawaban terbaik.
Marcin Adamczyk
Saya mendapat kesalahan ini: ** (UndefinedFunctionError) function Decimal.new/1 tidak ditentukan (modul Desimal tidak tersedia)
Daniel Cukier
4

Masalah dengan menggunakan Integer.parse/1adalah bahwa is akan mengurai bagian non-numerik dari string selama berada di ujung ekor. Sebagai contoh:

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"}

Demikian pula String.to_integer/1hasilnya sebagai berikut:

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")

Sebagai gantinya, validasi string terlebih dahulu.

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

Ekspresi reguler bisa lebih sederhana (misalnya ^[0-9]*$) tergantung pada kasus penggunaan Anda.

Nibir Bora
sumber
0

Jika Anda ingin mengonversi string menjadi tipe numerik apa pun yang ada di dalam string & menghapus semua karakter lain, ini mungkin berlebihan, tetapi akan mengembalikan float jika float atau int jika int atau nil jika string tidak berisi tipe numerik.

@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.dll
sumber