how to insert char at multiple position from end of the string - ruby

input like this:
100000000
1000
100
100000
10000
i need to start inserting char (,) from end of the string.first time after three char from end and then repeat the insert (,) after every 2 char
output
10,00,00,000
1,000
100
1,00,000
10,000
any hint guys how can i do this, i need to start inserting char(',') from end of the string.
thanks!

Here are two ways, the first using a regular expression, the last just inserting commas in a loop.
a = %w| 100000000 1000 100 100000 10000 |
#=> ["100000000", "1000", "100", "100000", "10000"]
#1 Use a regex
r = /
(?<=\d) # match digit in positive lookbehind
\d{2} # match two digits
(?= # begin positive lookahead
(?:\d{2})* # match two digits, repeated zero or more times
\d # match last digit
\z # match end of string
) # end positive lookahead
/x # extended mode
a.each { |s| puts "#{s} -> #{ s.gsub(r) { |ss| ',' + ss } }" }
100000000 -> 10,00,00,000
1000 -> 1,000
100 -> 100
100000 -> 1,00,000
10000 -> 10,000
This regex is similar to the one given earlier by #Avinish, but I chose to use a positive lookbehind and no capture group, and presented it in extended mode to help readers understand how it worked. I would use a regular expression here.
#2 Insert commas
If you do not wish to use a regular expression, you could determine the position of the last comma to insert (p below), the number of commas to insert (n below) and then insert them, back to front:
def insert_commas(string)
sz = string.size
str = string.dup
p = sz - 3
n = (sz - 2)/2
n.times { str.insert(p, ','); p -= 2 }
str
end
a.each { |s| puts "#{s} -> #{insert_commas(s)}" }
100000000 -> 10,00,00,000
1000 -> 1,000
100 -> 100
100000 -> 1,00,000
10000 -> 10,000
I duped string on the assumption you did not want to mutate string.
Alternatively,
def insert_commas(string)
sz = string.size
return string if sz < 4
p = sz.even? ? 1 : 2
string[0,p] + string[p..-2].gsub(/\d{2}/) { |s| ",#{s}" } + string[-1]
end

Use the below positive lookahead based regex.
gsub(/(\d)(?=(?:\d{2})*\d{3}$)/, "$1,")
DEMO

Related

Retain 0's when incrementing number

If I increment integer 003 by 1, I get 4.
num = 003
num += 1
# => 4
I want it to be 004. How can I retain the 0's in this?
You can convert an integer to a String and give it a fixed amount of padding using String#rjust, where the first argument is the total width of the resulting String, and the second argument is the character to use for padding:
>> int = 3
>> str = int.to_s.rjust(3, '0')
#=> "003"
And then you can increment that string using String#next:
>> str.next
#=> "004"
First of all, the leading zero in 003 makes that an octal integer literal in Ruby, not a decimal. Of course, it doesn't matter with 3 but it does matter for 009 (which is a SyntaxError), 030, etc. Presumably you really mean to say:
num = 3
as the leading zeroes aren't really part of the number, they're just formatting that you want on output. To format the number, you'd use String#% or sprintf:
> '%03d' % 3
=> "003"
> sprintf('%03d', 3)
=> "003"

summing up string representation of year and month durations in ruby

I was wondering if there is a way to sum up multiple durations in string representations like 2 years 2 months, 10 months, 3 years and output 6 years
You could do that as follows.
str = "2 years 4 months, 10 months, 3 years, 1 month"
r = /
(\d+) # match one or more digits in capture group 1
\s+ # match one or more whitespace chars
(year|month) # match 'year' or 'month' in capture group 2
s? # optionally match 's'
\b # match a word break
/x # free-spacing regex definition mode
a = str.scan r
#=> [["2", "year"], ["4", "month"], ["10", "month"], ["3", "year"], ["1", "month"]]
h = a.each_with_object(Hash.new(0)) { |(n,period),h| h[period] += n.to_i }
#=> {"year"=>5, "month"=>15}
y, m = h["month"].divmod(12)
#=> [1, 3]
h["year"] += y
#=> 6
h["month"] = m
#=> 3
h #=> {"year"=>6, "month"=>3}
Notes:
As noted in the doc for String#scan, "If the pattern contains groups, each individual result is itself an array containing one entry per group."
Hash.new(0) creates an empty hash with a default value of zero, meaning that if that hash h does not have a key k, h[k] returns zero. Thos is sometimes called a counting hash. See the doc for Hash::new.
Numeric#divmod is a useful and greatly-underused method.

Is it better way to do that?

I wrote a simple script to sum all digits of positive integer input until 1 digit is left ( for example for input 12345 result is 6 because 1+2+3+4+5 = 15 and 1+5 = 6). It works but is it better way to do that? ( more correct?)
here is a code:
def sum(n)
string=n.to_s
while string.length > 1 do
result=string.chars.inject { |sum,n| sum = sum.to_i + n.to_i}
string=result.to_s
end
puts "Sum of digits is " + string
end
begin
p "please enter a positive integer number:"
number = Integer(gets.chomp)
while number<0
p "Number must be positive!Enter again:"
number = Integer(gets.chomp)
end
rescue
p "You didnt enter integer!:"
retry
end
sum(number)
According to Wikipedia, the formula is:
dr(n) = 1 + ((n − 1) mod 9)
So it boils down to:
def sum(n)
1 + (n - 1) % 9
end
To account for 0, you can add return 0 if n.zero?
You could use divmod (quotient and modulus) to calculate the digit sum without converting to / from string. Something like this should work:
def sum(number)
result = 0
while number > 0 do
number, digit = number.divmod(10)
result += digit
if number == 0 && result >= 10
number = result
result = 0
end
end
result
end
sum(12345) #=> 6
The line
number, digit = number.divmod(10)
basically strips off the last digit:
12345.divmod(10) #=> [1234, 5]
1234 becomes the new number and 5 is being added to result. If number eventually becomes zero and result is equal or greater than 10 (i.e. more than one digit), result becomes the new number (e.g. 15) and the loops starts over. If result is below 10 (i.e. one digit), the loop exits and result is returned.
Short recursive version:
def sum_of_digits(digits)
sum = digits.chars.map(&:to_i).reduce(&:+).to_s
sum.size > 1 ? sum_of_digits(sum) : sum
end
p sum_of_digits('12345') #=> "6"
Single call version:
def sum_of_digits(digits)
digits = digits.chars.map(&:to_i).reduce(&:+).to_s until digits.size == 1
return digits
end
It's looking good to me. You might do things a little more conscise like use map to turn every char into an integer.
def sum(n)
string=n.to_s
while string.length > 1 do
result = string.chars.map(&:to_i).inject(&:+)
string = result.to_s
end
puts "Sum of digits is " + string
end
You could also use .digits, so you don't have to convert the input into a string.
def digital_root(n)
while n.digits.count > 1
array = n.digits
n = array.sum
end
return n
end

regex to pull in number with decimal or comma

This is my line of code:
col_value = line_item[column].scan(/\d+./).join().to_i
When I enter 30,000 into the textfield, col_value is 30.
I want it to bring in any number:
30,000
30.5
30.55
30000
Any of these are valid...
Is there a problem with the scan and or join which would cause it to return 30? Using the suggested regexes below still retunrs 30 e.g.
col_value = line_item[column].scan(/\d+[,.]?\d+/).join().to_i
Could it be that "to_i" converts "30,000" to 30??
This regex will match you desired output:
\d+[,.]?\d*
here ? is used as optional to match.
DEMO
\d+(?:[,.]\d+)?
Try this.This should do it for you.
Yes, "30,000".to_i #=> 30". See String#to_i: "Extraneous characters past the end of a valid number are ignored."
I suggest you first remove the commas, then apply a regex:
R = /
\d+ # match >= 0 digits
| # or
\d+\.\d+ # match > 0 digits, a decimal point, then > 0 digits
/x # extended mode
str = "30,000 30.5 30.55 30000 1. .1"
str1 = str.tr(',','')
#=> "30000 30.5 30.55 30000 1. .1"
a = str1.scan(R)
#=> ["30000", "30", "5", "30", "55", "30000"]
a.map(&:to_i)
#=> [30000, 30, 5, 30, 55, 30000]
After chaining, we have:
str.tr(',','').scan(R).map(&:to_i)
If the desired solution is instead:
#=> [30000, 30, 5, 30, 55, 30000, 1, 0]
the regex needs to be modified as follows:
R = /
\d+ # match >= 0 digits
| # or
\d+\.\d+ # match > 0 digits, a decimal point, then > 0 digits
| # or
\d+\. # match > 0 digits, then a decimal point
| # or
\.\d+ # match a decimal point, then > 0 digits
/x # extended mode

ruby number to human-readable string conversion

I need to have a list with id's for each list item being #one, #two etc.
Is this the most efficient way or am I missing an in built ruby function here?
-num_array = ["one", "two", "three", "four", "five", "six", "seven"]
-navigation[:primary_level].each_with_index do |primary_item, idx|
%li{ :id => "#{num_array[idx]}"}
The humanize gem converts digits into words.
Outside of using the humanize gem, using a hash would be way easier than the array stuff:
lookup = {"one" => 1, "two" => 2, "three" => 3, etc...}
text = "two"
num = lookup[text]
I'm sure this goes well beyond what you need, but there's code to do that at Rosetta Code
Here's my attempt at a solution in Ruby. It is likely suboptimal and has not been checked for correctness.
<<documentation
Converting Numbers to Human Readable Pretty Print Strings
General Description
===================
- Divide the number into groups of three
- e.g. turn 87012940 -> 87,012,940
- Parse each individual group
- e.g. 940 -> "nine hundred forty"
- Only parse the rightmost two numbers
- 0 -> 12: special cases; use hardcoded switch statements
- e.g. "one, two, three ... ten, eleven, twelve"
- 13 -> 19: same hardcoded switch statement + a "-teen" prefix
- e.g. "thirteen, fourteen, fifteen ... nineteen"
- 20 -> 99:
- Parse left digit and return according to the following rule:
- "twenty, thirty, forty, fifty, sixty ... ninety"
- Return the simple name of the right digit:
- "one, two, nine"
- special case: zero -> ""
- This is because the hundredth's place follows a simple prefix rule
- e.g. one-hundred, two-hundred, three-hundred ... nine-hundred
- special case: zero -> " "
- Add place modifiers according to each group's placement
- e.g. the middle '012' -> "twelve thousand"
- Concatenate all and return as solution
Algorithm (slightly modified)
=============================
Modifications
-------------
- No need to divide number into groups of three; simply parse right-to-left one at a time
- When finished processing one group, insert the result leftmost into our final solution string
documentation
def convert(num)
return 'zero' if (num == 0)
answer = ''
places = ['',
'thousand ',
'million ',
'billion ',
'trillion ',
'quadrillion ',
'quintillion ']
place = 0
loop do
break if num == 0
# Get the rightmost group of three
first_three_digits = num % 1000
# Truncate the original number by those three digits
num /= 1000
answer.insert(0, convert_group_of_three(first_three_digits) + places[place])
place += 1
end
answer.strip!
end
def convert_group_of_three(num)
str = ''
# Zero returns an empty string
special_cases = ['', 'one ', 'two ', 'three ', 'four ', 'five ', 'six ', 'seven ', 'eight ', 'nine ', 'ten ',
'eleven ', 'twelve ', 'thirteen ', 'fourteen ', 'fifteen ', 'sixteen ', 'seventeen ', 'eighteen ', 'nineteen ']
return special_cases[num % 100] if (0 .. special_cases.length - 1).include? (num % 100)
# If not in special cases, num must be at least a two digit number
# Pull the first digit
first_digit = num % 10
num /= 10
str.insert(0, special_cases[first_digit])
# Pull the second digit
second_digit = num % 10
num /= 10
second_digit_str = ''
case second_digit
when 2
second_digit_str = 'twenty '
when 3
second_digit_str = 'thirty '
when 4
second_digit_str = 'forty '
when 5
second_digit_str = 'fifty '
when 6
second_digit_str = 'sixty '
when 7
second_digit_str = 'seventy '
when 8
second_digit_str = 'eighty '
when 9
second_digit_str = 'ninety '
end
str.insert(0, second_digit_str)
# If there is a third digit
if num > 0
third_digit = num % 10
str.insert(0, special_cases[third_digit] + 'hundred ')
end
str
end
p convert(2389475623984756)
Output:
"two quadrillion three hundred eighty nine trillion four hundred seventy five billion six hundred twenty three million nine hundred eighty four thousand seven hundred fifty six"

Resources