Tl; dr: Utilisez une approche regex. Il est 39 fois plus rapide que l'approche de sauvetage dans la réponse acceptée et gère également des cas tels que "1 000"
def regex_is_number? string
no_commas = string.gsub(',', '')
matches = no_commas.match(/-?\d+(?:\.\d+)?/)
if !matches.nil? && matches.size == 1 && matches[0] == no_commas
true
else
false
end
end
-
La réponse acceptée par @Jakob S fonctionne pour la plupart, mais attraper des exceptions peut être très lent. De plus, l'approche de sauvetage échoue sur une chaîne comme "1,000".
Définissons les méthodes:
def rescue_is_number? string
true if Float(string) rescue false
end
def regex_is_number? string
no_commas = string.gsub(',', '')
matches = no_commas.match(/-?\d+(?:\.\d+)?/)
if !matches.nil? && matches.size == 1 && matches[0] == no_commas
true
else
false
end
end
Et maintenant quelques cas de test:
test_cases = {
true => ["5.5", "23", "-123", "1,234,123"],
false => ["hello", "99designs", "(123)456-7890"]
}
Et un peu de code pour exécuter les cas de test:
test_cases.each do |expected_answer, cases|
cases.each do |test_case|
if rescue_is_number?(test_case) != expected_answer
puts "**rescue_is_number? got #{test_case} wrong**"
else
puts "rescue_is_number? got #{test_case} right"
end
if regex_is_number?(test_case) != expected_answer
puts "**regex_is_number? got #{test_case} wrong**"
else
puts "regex_is_number? got #{test_case} right"
end
end
end
Voici la sortie des cas de test:
rescue_is_number? got 5.5 right
regex_is_number? got 5.5 right
rescue_is_number? got 23 right
regex_is_number? got 23 right
rescue_is_number? got -123 right
regex_is_number? got -123 right
**rescue_is_number? got 1,234,123 wrong**
regex_is_number? got 1,234,123 right
rescue_is_number? got hello right
regex_is_number? got hello right
rescue_is_number? got 99designs right
regex_is_number? got 99designs right
rescue_is_number? got (123)456-7890 right
regex_is_number? got (123)456-7890 right
Il est temps de faire quelques benchmarks de performance:
Benchmark.ips do |x|
x.report("rescue") { test_cases.values.flatten.each { |c| rescue_is_number? c } }
x.report("regex") { test_cases.values.flatten.each { |c| regex_is_number? c } }
x.compare!
end
Et les résultats:
Calculating -------------------------------------
rescue 128.000 i/100ms
regex 4.649k i/100ms
-------------------------------------------------
rescue 1.348k (±16.8%) i/s - 6.656k
regex 52.113k (± 7.8%) i/s - 260.344k
Comparison:
regex: 52113.3 i/s
rescue: 1347.5 i/s - 38.67x slower