Is there a method to extract integers from a string? - ruby

It seems that String#to_i only works when numbers are leading in a string.
Works:
"123acb".to_i #=> 123
Doesn't work, but what I'm trying to accomplish:
"abc123def".to_i #=> 123
I've been looking for a built in method to do this but I haven't found one. Is my only option to use a regular expression?
EDIT -
Wow! Lots of good options! As an aside, was there any specific reason why to_i only deals with leading numbers?

What about doing something like this?
"abc123def".gsub(/\D/, '').to_i
# => 123
If you want to handle multiple numbers inside a big string, you can do
"a22bc123de4f004".split(/\D/).reject(&:empty?).map(&:to_i)
# => [22, 123, 4, 004]

Here's another approach, using scan rather than split:
>> "abc123def456ghi".scan(/\d+/).join.to_i
=> 123456
Note that scan keeps while split throws away....
To answer the actual question "is there a built-in method to do this?" you can see from the Ruby String class documentation that there isn't, unless you take scan, split, to_i, delete and friends as "close enough" to being built-in.

"abc123def"[/\d+/].to_i
# => 123

Another one using delete
"abc123def456ghi".delete("^0-9").to_i
# => 123456

How about the below using String#tr ?
"abc123def456ghi".tr('a-z','').to_i
# => 123456
"abc123def456ghiA".tr('A-z','').to_i
# => 123456

Related

Easy way to convert numbers into ordinals in words

Any easy way to convert 1 into "first" and 2 into "second", etc? Even if it's a library or a gem, any suggestions would be helpful.
My favorite is to use the twitter_cldr gem.
require "twitter_cldr"
1.localize(:en).to_rbnf_s("SpelloutRules", "spellout-ordinal") # => "first"
2.localize(:en).to_rbnf_s("SpelloutRules", "spellout-ordinal") # => "second"
I'm only aware of active_support's ordinalize. The following example produces 1st, 2nd, 3rd, which isn't exactly as the question asked.
1.ordinalize # returns "1st"
2.ordinalize # returns "2nd"

Ruby on Rails - How do I split string and Number?

I have a string "FooFoo2014".
I want the result to be => "Foo Foo 2014"
Any idea?
This works fine:
puts "FooFoo2014".scan(/(\d+|[A-Z][a-z]+)/).join(' ')
# => Foo Foo 2014
Of course in condition that you separate numbers and words from capital letter.
"FooFoo2014"
.gsub(/(?<=\d)(?=\D)|(?<=\D)(?=\d)|(?<=[a-z])(?=[A-Z])/, " ")
# => "Foo Foo 2014"
Your example is a little generic. So this might be guessing in the wrong direction. That being said, it seems like you want to reformat the string a little:
"FooFoo2014".scan(/^([A-Z].*)([A-Z].*\D*)(\d+)$/).flatten.join(" ")
As "FooFoo2014" is a string with some internal structure important to you, you need to come up with the right regular expression yourself.
From your question, I extract two tasks:
split the FooFoo at the capital letter.
/([A-Z].*)([A-Z].*)/ would do that, given you only have standard latin letters
split the letter from the digits
/(.*\D)(\d+)/ achieves that.
The result of scan is an array in my version of ruby. Please verify that in your setup.
If you think that regular expressions are too complicated for this, I suggest that you take a good look into ActiveSupport. http://api.rubyonrails.org/v3.2.1/ might help you.
If its only letters then only digits:
target = "FooFoo2014"
match_data = target.match(/([A-Za-z]+)(\d+)/)
p match_data[1] # => "FooFoo"
p match_data[2] # => "2014
If it is two words each made of one capitalized letter then lowercase letters, then digits:
target = "FooBar2014"
match_data = target.match(/([A-Z][a-z]+)([A-Z][a-z]+)(\d+)/)
p match_data[1] # => "Foo"
p match_data[2] # => "Bar"
p match_data[3] # => "2014
Better regex are probably possible.

Ruby split on numbers vs letters

I'd like to split the following string on letters:
1234B
There are always only ever 4 digits and one letter. I just want to split those out.
Here is my attempt, I think I have the method right and the regex matches the number but I dont think my syntax or my regex is pertinent to the problem Im attempting to solve.
"1234A".split(/^\d{4}/)
What you want is not clear, but a general solution to this kind of situation is:
"1234A".scan(/\d+|\D+/)
# => ["1234", "A"]
If there are always 4 digits and 1 letter, there's no need to use regular expressions to split the string. Just do this:
str = "1234A"
digits,letter = str[0..3],str[4]
Looking at it purely from the perspective of splitting any string into groups of 4:
"1234A".scan(/.{1,4}/)
# => ["1234", "A"]
Another no-regex version:
str = "1234A"
str.chars.to_a.last # => "A"
str.chop # => "1234"

How does Ruby's replace work?

I'm looking at ruby's replace: http://www.ruby-doc.org/core/classes/String.html#M001144
It doesn't seem to make sense to me, you call replace and it replaces the entire string.
I was expecting:
replace(old_value, new_value)
Is what I am looking for gsub then?
replace seems to be different than in most other languages.
I agree that replace is generally used as some sort of pattern replace in other languages, but Ruby is different :)
Yes, you are thinking of gsub:
ruby-1.9.2-p136 :001 > "Hello World!".gsub("World", "Earth")
=> "Hello Earth!"
One thing to note is that String#replace may seem pointeless, however it does remove 'taintediness". You can read more up on tained objects here.
I suppose the reason you feel that replace does not make sense is because there is assigment operator = (not much relevant to gsub).
The important point is that String instances are mutable objects. By using replace, you can change the content of the string while retaining its identity as an object. Compare:
a = 'Hello' # => 'Hello'
a.object_id # => 84793190
a.replace('World') # => 'World'
a.object_id # => 84793190
a = 'World' # => 'World'
a.object_id # => 84768100
See that replace has not changed the string object's id, whereas simple assignment did change it. This difference has some consequences. For example, suppose you assigned some instance variables to the string instance. By replace, that information will be retained, but if you assign the same variable simply to a different string, all that information is gone.
Yes, it is gsub and it is taken from awk syntax. I guess replace stands for the internal representation of the string, since, according to documentation, tainted-ness is removed too.

English Sentence to Camel-cased method name

I had to convert a series of sentences into camel-cased method names. I ended writing something for it. I am still curious if there's something simpler for it.
Given the string a = "This is a test." output thisIsATest
I used for following:
a.downcase.gsub(/\s\w/){|b| b[-1,1].upcase }
Not sure it's better as your solution but it should do the trick:
>> "This is a test.".titleize.split(" ").join.camelize(:lower)
=> "thisIsATest."
titleize: uppercase every first letter of each word
split(" ").join: create an array with each word and join to squeeze the spaces out
camelize(:lower): make the first letter lowercase
You can find some more fun functions in the Rails docs: http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html
"active_record".camelize(:lower)
output : "activeRecord"
use these
"Some string for you".gsub(/\s+/,'_').camelize(:lower) #=> "someStringForYou"
gsub: Replace spaces by underscores
camelize: java-like method camelcase
You might try using the 'English' gem, available at http://english.rubyforge.org/
require 'english/case'
a = "This is a test."
a.camelcase().uncapitalize() # => 'thisIsATest

Resources