Câu trả lời:
Kiểm tra Integer.parse/1và Float.parse/1.
Integer.parse/1hơn String.to_integer/1không?
Integer.parse/1trả về một :errornguyên tử nếu không thành công. String.to_integer/1ném a (FunctionClauseError).
Ngoài các chức năng Integer.parse/1và Float.parse/1mà José đã đề xuất, bạn cũng có thể kiểm tra String.to_integer/1và String.to_float/1.
Gợi ý: Xem thêm to_atom/1, to_char_list/1, to_existing_atom/1cho 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_integerhoạt động tốt nhưng String.to_floatkhó 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_floatchỉ có thể xử lý float được định dạng tốt, ví dụ:, 1.0not 1(số nguyên). Điều đó đã được ghi lại trong tài liệu String.to_floatcủ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.parsetrả 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/1hoặ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 endmà 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/1là 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/1có 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