ruby - section - wbr tag in html5
AnĂ¡lisis entero seguro en Ruby (8)
Tengo una cadena, digamos ''123''
, y quiero convertirla a 123
.
Sé que puedes simplemente hacer some_string.to_i
, pero eso convierte a ''lolipops''
en 0
, que no es el efecto que tengo en mente. Quiero que explote en mi cara cuando trato de convertir algo inválido, con una agradable y dolorosa Exception
. De lo contrario, no puedo distinguir entre un 0
válido y algo que simplemente no es un número en absoluto.
EDITAR: Estaba buscando la forma estándar de hacerlo, sin engaños regex.
Esto podría funcionar:
i.to_i if i.match(/^/d+$/)
Me gusta la respuesta de Myron, pero sufre de la enfermedad de Ruby de "Ya no uso Java / C #, así que nunca volveré a utilizar la herencia" . Abrir cualquier clase puede ser peligroso y debe usarse con moderación, especialmente cuando es parte de la biblioteca principal de Ruby. No digo que nunca lo use, pero generalmente es fácil de evitar y hay mejores opciones disponibles, por ejemplo
class IntegerInString < String
def initialize( s )
fail ArgumentError, "The string ''#{s}'' is not an integer in a string, it''s just a string." unless s =~ /^/-?[0-9]+$/
super
end
end
Entonces, cuando desee utilizar una cadena que podría ser un número, está claro lo que está haciendo y no le molesta a ninguna clase central, por ejemplo
n = IntegerInString.new "2"
n.to_i
# => 2
IntegerInString.new "blob"
ArgumentError: The string ''blob'' is not an integer in a string, it''s just a string.
Puede agregar todo tipo de otras comprobaciones en la inicialización, como buscar números binarios, etc. Lo principal, sin embargo, es que Ruby es para las personas y para las personas significa claridad . Nombrar un objeto a través de su nombre de variable y su nombre de clase hace las cosas mucho más claras.
Otro comportamiento inesperado con la solución aceptada (con 1.8, 1.9 está bien):
>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025
así que si no está seguro de lo que se está transmitiendo, asegúrese de agregar un .to_s
.
Su implementación permite el paso de "1a" o "b2". ¿Qué tal esto en su lugar?
def safeParse2(strToParse)
if strToParse =~ //A/d+/Z/
strToParse.to_i
else
raise Exception
end
end
["100", "1a", "b2", "t"].each do |number|
begin
puts safeParse2(number)
rescue Exception
puts "#{number} is invalid"
end
end
Esto produce:
100
1a is invalid
b2 is invalid
t is invalid
Ruby tiene esta funcionalidad integrada:
Integer(''1001'') # => 1001
Integer(''1001 nights'')
# ArgumentError: invalid value for Integer: "1001 nights"
Como señaló Joseph Pecoraro en su respuesta, es posible que desee buscar cadenas que sean números válidos no decimales, como los que comienzan con 0x
para hexadecimal y 0b
para binario, y potencialmente más complicados comenzando con cero que se analizarán como octal .
Ruby 1.9.2 añadió un segundo argumento opcional para radix, por lo que se puede evitar el problema anterior:
Integer(''23'') # => 23
Integer(''0x23'') # => 35
Integer(''023'') # => 19
Integer(''0x23'', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer(''023'', 10) # => 23
También tenga en cuenta los efectos que la solución aceptada actual puede tener en el análisis de números hexadecimales, octales y binarios:
>> Integer(''0x15'')
# => 21
>> Integer(''0b10'')
# => 2
>> Integer(''077'')
# => 63
En Ruby, los números que comienzan con 0x
o 0X
son hexadecimales, 0b
o 0B
son binarios, y solo 0
son octal. Si este no es el comportamiento deseado, puede combinarlo con algunas de las otras soluciones que comprueban si la cadena coincide primero con un patrón. Como las expresiones //d+/
regulares, etc.
Tuve que lidiar con esto en mi último proyecto, y mi implementación fue similar, pero un poco diferente:
class NotAnIntError < StandardError
end
class String
def is_int?
self =~ /^-?[0-9]+$/
end
def safe_to_i
return self.to_i if is_int?
raise NotAnIntError, "The string ''#{self}'' is not a valid integer.", caller
end
end
class Integer
def safe_to_i
return self
end
end
class StringExtensions < Test::Unit::TestCase
def test_is_int
assert "98234".is_int?
assert "-2342".is_int?
assert "02342".is_int?
assert !"+342".is_int?
assert !"3-42".is_int?
assert !"342.234".is_int?
assert !"a342".is_int?
assert !"342a".is_int?
end
def test_safe_to_i
assert 234234 == 234234.safe_to_i
assert 237 == "237".safe_to_i
begin
"a word".safe_to_i
fail ''safe_to_i did not raise the expected error.''
rescue NotAnIntError
# this is what we expect..
end
end
end
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
puts "oops, this isn''t a number"
end
Probablemente no sea la forma más limpia de hacerlo, pero debería funcionar.