Câu trả lời:
Kiểm tra Integer.parse/1
và Float.parse/1
.
Integer.parse/1
hơn String.to_integer/1
không?
Integer.parse/1
trả về một :error
nguyên tử nếu không thành công. String.to_integer/1
ném a (FunctionClauseError)
.
Ngoài các chức năng Integer.parse/1
và Float.parse/1
mà José đã đề xuất, bạn cũng có thể kiểm tra String.to_integer/1
và String.to_float/1
.
Gợi ý: Xem thêm to_atom/1
, to_char_list/1
, to_existing_atom/1
cho chuyển đổi khác.
Cảm ơn mọi người trên trang này, chỉ cần đơn giản hóa một câu trả lời ở đây:
{intVal, ""} = Integer.parse(val)
vì nó xác nhận rằng toàn bộ chuỗi đã được phân tích cú pháp (không chỉ là tiền tố).
Có 4 hàm để tạo số từ chuỗi
String.to_integer
hoạt động tốt nhưng String.to_float
khó hơn:
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
Như String.to_float
chỉ có thể xử lý float được định dạng tốt, ví dụ:, 1.0
not 1
(số nguyên). Điều đó đã được ghi lại trong tài liệu String.to_float
của
Trả về một float có biểu diễn văn bản là chuỗi.
chuỗi phải là biểu diễn chuỗi của một số thực bao gồm dấu thập phân. Để phân tích cú pháp một chuỗi không có dấu thập phân dưới dạng float thì nên sử dụng Float.parse / 1. Nếu không, ArgumentError sẽ xuất hiện.
Nhưng Float.parse
trả về một bộ gồm 2 phần tử, không phải là số bạn muốn, vì vậy việc đặt nó vào đường ống không phải là "mát mẻ":
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]
Sử dụng elem
để lấy phần tử đầu tiên từ tuple làm cho nó ngắn hơn và ngọt ngào hơn:
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]
Bạn có thể chuyển nó thành char_list và sau đó sử dụng Erlang to_integer/1
hoặc to_float/1
.
Ví dụ
iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}
iex> myInt
23
fn q -> {v, _} = Float.parse(q); v end
mà tôi không thích. Tôi thích sử dụng nó trong Enum.map
, ví dụ: list |> Enum.map(&String.to_float/1)
nhưng string.to_float không hoạt động với các số nguyên?
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
Vấn đề với việc sử dụng Integer.parse/1
là sẽ phân tích cú pháp bất kỳ phần không phải số nào của chuỗi miễn là nó nằm ở phần cuối đuôi. Ví dụ:
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"}
Tương tự String.to_integer/1
có kết quả sau:
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")
Thay vào đó, hãy xác thực chuỗi trước.
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
Biểu thức chính quy có thể đơn giản hơn (ví dụ ^[0-9]*$
) tùy thuộc vào trường hợp sử dụng của bạn.
Nếu bạn muốn chuyển đổi một chuỗi thành bất kỳ kiểu số nào trong chuỗi và xóa tất cả các ký tự khác, điều này có thể là quá mức cần thiết, nhưng sẽ trả về một số float nếu nó là float hoặc int nếu là int hoặc nil nếu chuỗi không chứa một kiểu số.
@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