Parsing a Number from a String

Problem

Given a string that contains some representation of a number, you want to get the corresponding integer or floating-point value.

Solution

Use String#to_i to turn a string into an integer. Use String#to_f to turn a string into a floating-point number.

	'400'.to_i # => 400
	'3.14'.to_f # => 3.14
	'1.602e-19'.to_f # => 1.602e-19

 

Discussion

Unlike Perl and PHP, Ruby does not automatically make a number out of a string that contains a number. You must explicitly call a conversion method that tells Ruby how you want the string to be converted.

Along with to_i and to_f, there are other ways to convert strings into numbers. If you have a string that represents a hex or octal string, you can call String#hex or String#oct to get the decimal equivalent. This is the same as passing the base of the number into to_i:

	'405'.oct # => 261
	'405'.to_i(8) # => 261
	'405'.hex # => 1029
	'405'.to_i(16) # => 1029
	'fed'.hex # => 4077
	'fed'.to_i(16) # => 4077

If to_i, to_f, hex,or oct find a character that can't be part of the kind of number they're looking for, they stop processing the string at that character and return the number so far. If the string's first character is unusable, the result is zero.

	"13: a baker's dozen".to_i # => 13
	'1001 Nights'.to_i # => 1001
	'The 1000 Nights and a Night'.to_i # => 0
	'60.50 Misc. Agricultural Equipment'.to_f # => 60.5
	'$60.50'.to_f # => 0.0
	'Feed the monster!'.hex # => 65261
	'I fed the monster at Canoga Park Waterslides'.hex # => 0
	'0xA2Z'.hex # => 162
	'-10'.oct # => -8
	'-109'.oct # => -8
	'3.14'.to_i # => 3

Note especially that last example: the decimal point is just one more character that stops processing of a string representing an integer.

If you want an exception when a string can't be completely parsed as a number, use Integer( ) or Float( ):

	Integer('1001') # => 1001
	Integer('1001 nights')
	# ArgumentError: invalid value for Integer: "1001 nights"

	Float('99.44') # => 99.44
	Float('99.44% pure')
	# ArgumentError: invalid value for Float(): "99.44% pure"

To extract a number from within a larger string, use a regular expression. The NumberParser class below contains regular expressions for extracting floating-point strings, as well as decimal, octal, and hexadecimal numbers. Its extract_numbers method uses String#scan to find all the numbers of a certain type in a string.

	class NumberParser
	 @@number_regexps = {
	 :to_i => /([+-]?[0-9]+)/,
	 :to_f => /([+-]?([0-9]*.)?[0-9]+(e[+-]?[0-9]+)?)/i,
	 :oct => /([+-]?[0-7]+)/,
	 :hex => /([+-]?(0x)?[0-9a-f]+)/i
	 #The  characters prevent every letter A-F in a word from being
	 #considered a hexadecimal number.
	 }

	 def NumberParser.re( 
parsing_method=:to_i)
	 re = @@number_regexps[ 
parsing_method]
	 raise ArgumentError, "No regexp for #{parsing_method.inspect}!" unless re
	 return re
	 end

	 def extract(s, parsing_method=:to_i)
	 
numbers = []
	 s.scan(NumberParser.re(parsing_method)) do |match|
	 numbers << match[0].send(parsing_method)
	 end
	 numbers
	 end
	end

Here it is in action:

	p = NumberParser.new

	pw = "Today's numbers are 104 and 391."
	NumberParser.re(:to_i).match(pw).captures # => ["104"]
	p.extract(pw, :to_i) # => [104, 391]

	p.extract('The 1000 nights and a night') # => [1000]
	p.extract('$60.50', :to_f) # => [60.5]
	p.extract('I fed the monster at Canoga Park Waterslides', :hex)
	# => [4077]
	p.extract('In octal, fifteen is 017.', :oct) # => [15]

	p.extract('From 0 to 10e60 in -2.4 seconds', :to_f)
	# => [0.0, 1.0e+61, -2.4]
	p.extract('From 0 to 10e60 in -2.4 seconds')
	# => [0, 10, 60, -2, 4]

If you want to extract more than one kind of number from a string, the most reliable strategy is to stop using regular expressions and start using the scanf module, a free third-party module that provides a parser similar to C's scanf function.

	require 'scanf'
	s = '0x10 4.44 10'.scanf('%x %f %d') # => [16, 4.44, 10]

 

See Also

  • Recipe 2.6, "Converting Between Numeric Bases"
  • Recipe 8.9, "Converting and Coercing Objects to Different Types"
  • The scanf module (http://www.rubyhacker.com/code/scanf/)


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net