tôi thấy các cuộc thảo luận chưa được giải quyết trên cast + ngoại lệ vs regex và tôi nghĩ rằng tôi sẽ cố gắng để mọi thứ chuẩn mực và tạo ra một câu trả lời khách quan:
Đây là nguồn cho các trường hợp tốt nhất và tồi tệ nhất của mỗi phương pháp cố gắng ở đây:
require "benchmark"
n = 500000
def is_float?(fl)
!!Float(fl) rescue false
end
def is_float_reg(fl)
fl =~ /(^(\d+)(\.)?(\d+)?)|(^(\d+)?(\.)(\d+))/
end
class String
def to_float
Float self rescue (0.0/0.0)
end
end
Benchmark.bm(7) do |x|
x.report("Using cast best case") {
n.times do |i|
temp_fl = "#{i + 0.5}"
is_float?(temp_fl)
end
}
x.report("Using cast worst case") {
n.times do |i|
temp_fl = "asdf#{i + 0.5}"
is_float?(temp_fl)
end
}
x.report("Using cast2 best case") {
n.times do |i|
"#{i + 0.5}".to_float
end
}
x.report("Using cast2 worst case") {
n.times do |i|
"asdf#{i + 0.5}".to_float
end
}
x.report("Using regexp short") {
n.times do |i|
temp_fl = "#{i + 0.5}"
is_float_reg(temp_fl)
end
}
x.report("Using regexp long") {
n.times do |i|
temp_fl = "12340918234981234#{i + 0.5}"
is_float_reg(temp_fl)
end
}
x.report("Using regexp short fail") {
n.times do |i|
temp_fl = "asdf#{i + 0.5}"
is_float_reg(temp_fl)
end
}
x.report("Using regexp long fail") {
n.times do |i|
temp_fl = "12340918234981234#{i + 0.5}asdf"
is_float_reg(temp_fl)
end
}
end
với những kết quả sau đây với mri193:
user system total real
Using cast best case 0.608000 0.000000 0.608000 ( 0.615000)
Using cast worst case 5.647000 0.094000 5.741000 ( 5.745000)
Using cast2 best case 0.593000 0.000000 0.593000 ( 0.586000)
Using cast2 worst case 5.788000 0.047000 5.835000 ( 5.839000)
Using regexp short 0.951000 0.000000 0.951000 ( 0.952000)
Using regexp long 1.217000 0.000000 1.217000 ( 1.214000)
Using regexp short fail 1.201000 0.000000 1.201000 ( 1.202000)
Using regexp long fail 1.295000 0.000000 1.295000 ( 1.284000)
Vì chúng ta chỉ xử lý các thuật toán thời gian tuyến tính nên tôi nghĩ chúng ta sử dụng các phép đo thực nghiệm để tạo khái quát. Nó là đồng bằng để thấy rằng regex là phù hợp hơn và sẽ chỉ dao động một chút dựa trên độ dài của chuỗi thông qua. Các diễn viên rõ ràng là nhanh hơn khi không có thất bại, và chậm hơn nhiều khi có thất bại.
Nếu chúng ta so sánh thời gian thành công, chúng ta có thể thấy rằng trường hợp đúc tốt nhất là khoảng .3 giây nhanh hơn so với trường hợp tốt nhất regex. Nếu chúng ta chia số lượng này cho khoảng thời gian trong trường hợp xấu nhất, chúng ta có thể ước tính có bao nhiêu lần chạy nó sẽ phá vỡ ngay cả với các ngoại lệ làm chậm quá trình cast xuống để phù hợp với tốc độ regex. Khoảng 6 giây dived bởi .3 cho chúng ta khoảng 20. Vì vậy, nếu hiệu suất các vấn đề và bạn mong đợi ít hơn 1 trong 20 của thử nghiệm của bạn để thất bại sau đó sử dụng cast + ngoại lệ.
JRuby 1.7.4 có kết quả hoàn toàn khác nhau:
user system total real
Using cast best case 2.575000 0.000000 2.575000 ( 2.575000)
Using cast worst case 53.260000 0.000000 53.260000 (53.260000)
Using cast2 best case 2.375000 0.000000 2.375000 ( 2.375000)
Using cast2 worst case 53.822000 0.000000 53.822000 (53.822000)
Using regexp short 2.637000 0.000000 2.637000 ( 2.637000)
Using regexp long 3.395000 0.000000 3.395000 ( 3.396000)
Using regexp short fail 3.072000 0.000000 3.072000 ( 3.073000)
Using regexp long fail 3.375000 0.000000 3.375000 ( 3.374000)
Cast chỉ là nhẹ nhanh hơn trong trường hợp tốt nhất (khoảng 10%). Giả sử sự khác biệt này là thích hợp để làm cho khái quát hóa (tôi không nghĩ nó là), sau đó điểm hòa vốn là một nơi nào đó giữa 200 và 250 chạy với chỉ 1 gây ra một ngoại lệ.
Vì vậy, ngoại lệ chỉ nên được sử dụng khi những điều thực sự đặc biệt xảy ra, đây là quyết định cho bạn và codebase của bạn. Khi họ không được sử dụng mã họ đang ở có thể được đơn giản và nhanh hơn.
Nếu hiệu suất không quan trọng, có lẽ bạn nên theo dõi bất kỳ quy ước nào mà bạn nhóm hoặc mã cơ sở đã có và bỏ qua toàn bộ câu trả lời này.
Câu trả lời hay! Lưu ý: Regex này đã phát triển một chút trong việc triển khai của Rubinius, xem thông số kỹ thuật tại https://github.com/rubinius/rubinius/blob/master/spec/ruby/core/string/to_f_spec.rb để biết chi tiết. Hãy nhớ rằng nếu bạn đang sử dụng điều này để xác nhận người dùng nhập vào, bạn có thể muốn bỏ hỗ trợ cho dấu gạch dưới và chỉ sử dụng regex Rubinius 'để cảm hứng :) – captainpete
Correction, Rubinius vẫn sử dụng cùng một regex cho Float(). Tìm mã tại https://github.com/rubinius/rubinius/blob/master/kernel/common/kernel19.rb – captainpete