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

Jawaban:


153

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.


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


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]

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

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

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.


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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.