Easy way to convert numbers into ordinals in words - ruby

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"

Related

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.

how to limit a regular expression to the closest in ruby

Assuming I have:
[24] pry(main)> str="these (are) things (that) I want (to) know"
and I want
=> ["these", "things", "I want", "know"]
but
[25] pry(main)> str.split(/\(.*\)/)
I get:
=> ["these ", " know"]
[26] pry(main)>
How would I fix this? Sorry for multiple questions - a bit seperate issues.
edit #1
since we're splitting on a Regex, is there any way to also get the matched elements back?
like:
=> [["these", "things", "I want", "know"],["(are)","(that)","(too)"]]
where the first part is the splitted values and the second is the matched array?
Make the * quantifier ungreedy by putting a ? after it. Like so:
str.split(/\(.*?\)/)
.* without ? will match as much as possible, while you want the opposite effect.
You could also use a different approach and restrict what characters you want to match. For example:
str.split(/\([^()]*\)/)
Non regexp version:
s = "these (are) things (that) I want (to) know"
is_parenthesised = -> x {x.start_with?('(') && x.end_with?(')')}
p s.split(' ').partition &is_parenthesised #=> [["(are)", "(that)", "(to)"], ["these", "things", "I", "want", "know"]]
Here's another way:
[str.gsub(/\s*\(.*?\)\s*/, 0.chr).split(0.chr), str.scan(/(\(.*?\))/).flatten]
#=> [["these", "things", "I want", "know"], ["(are)", "(that)", "(to)"]]
I could have gsub'ed to any string I was certain was not in the data. ASCII 0 seemed a safe choice. split is definitely better for the first element, but I offer this in the interest of diversity.

Is there a method to extract integers from a string?

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

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"

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