Written September 27, 2006. Tagged Ruby.

I wrote some Ruby code to convert positive decimal integers (like `123`

) or strings (like `"123"`

) into strings of Swedish (like `"etthundratjugotre"`

).

I was pleasantly surprised at how little code was needed. I suppose anything else would be odd (or contain redundant code), since it's a system of predictable patterns.

The code shouldn't be too hard to adapt for English or any other language with a similar numbers-to-words mapping to Swedish. Keep in mind that the names for large numbers vary even between American and British English.

The code was implemented as an `Integer.to_swedish`

class method (e.g. `Integer.to_swedish("123")`

), also available through an `Integer`

instance method (e.g. `123.to_swedish`

).

Every named power of ten listed in Swedish Wikipedia is handled, except for googolplex and googolplexian, being too large to store within the known universe.

Numbers recurse if necessary, so whereas the highest named number is "centiljard" (10^{603}), you can have any number of those, limited only by available memory.

The use of whitespace (between parts except within hundreds and tens) is obviously debatable.

The input is turned into a reverse array of digits, so `"123"`

becomes `[3,2,1]`

.

That array is turned into output (a list of strings, eventually joined together) starting at the beginning (the left-hand side) and moving towards the end.

Zeroes and empty input are given special treatment: the program bails early, returning the proper value, if they are present.

A private class method, `Integer.below_thousand`

handles the numbers 1–999. Its workings are rather obvious. If in the range 10–19, a stored "teen" value is chosen. If outside that range, singles and tens are appended to the output as appropriate. If there are any hundreds involved, those are appended to the output next.

The rest of the code basically consists of applying `Integer.unit`

to various named powers of ten and their ranges, in the right order. The input of this method is the entire number (in that reverse array representation), the name, and the positions of the number that this name ranges over. So e.g. thousands range from 10^{3} to 10^{5} (i.e. 1000–999 000 are some number of thousands). 10^{6} to 10^{8} is the range for millions, and so on. How many thousands, millions etc is determined recursively.

For the most part, it's just ten to the power of some multiple of three, which is a reason you don't need a lot of code. There is the odd exception, though, that needs special handling.

For the largest implemented named power of ten, "centiljarder", the range is from 10^{603} to the end of the input.

After joining the output together into a string, two regular expression substitutions are applied, to fix gender and number agreement issues.

The code (download):

`#! /usr/bin/env ruby`

# Henrik Nyh <https://henrik.nyh.se> 2006-09-27

# Free to modify and redistribute non-commercially with due credit.

# Turns integer strings into Swedish words. Handles units up to and including "centiljard", per <http://sv.wikipedia.org/wiki/R%C3%A4kneord#Lista_.C3.B6ver_r.C3.A4kneord>.

class Array

def singles; slice(0); end

def tens; slice(1); end

def hundreds; slice(2); end

def tens?

tens and tens.nonzero?

end

def hundreds?

hundreds and hundreds.nonzero?

end

def contain_positive_integers?

(1..9).any? {|int| self.include? int}

end

end

class Integer

SINGLES = %w{noll ett två tre fyra fem sex sju åtta nio}

TEENS = %w{tio elva tolv tretton fjorton femton sexton sjutton arton nitton}

TENS = %w{_ _ tjugo trettio fyrtio femtio sextio sjuttio åttio nittio}

HUNDREDS, GOOGOLS, CENTILLIONS, CENTILLIARDS = %w{hundra googoler centiljoner centiljarder}

CUBES = %w{tusen}

%w{m b tr kvadr kvint sext sept okt non dec undec duodec tredec quattuordec quindec sexdec septendec octodec novemdec vigint}.each do |prefix|

CUBES << "#{prefix}iljoner" << "#{prefix}iljarder"

end

def to_swedish

Integer.to_swedish(self)

end

def self.to_swedish(string)

number = string.to_s.scan(/\d/).map {|n| n.to_i}.reverse # "00123" becomes [3,2,1,0,0]

number.pop while number.size > 1 and number.last.zero?

return nil if number.empty?

return SINGLES[0] if number == [0]

output = below_thousand(number)

CUBES.each_with_index do |name,index|

exponent = (index + 1) * 3

case exponent

when 99 # special treatment for sexdeciljard since 10^100 is googol

output += unit(number, name, 99, 1)

output += unit(number, GOOGOLS, 100, 2)

when 123 # vigintiljard spans 10^123 - 10^599

output += unit(number, name, 123..599)

else

output += unit(number, name, exponent)

end

end

output += unit(number, CENTILLIONS, 600)

output += unit(number, CENTILLIARDS, 603..-1)

output = output.reverse.join(" ")

# Fix singular determiners

output.gsub!(/\bett (\w+)er/, 'en \1')

output.gsub!(/ett (\w+er)/, 'en \1')

output

end

private # Helper methods

def self.below_thousand(number) # Turns e.g. [3,2,1] (for 123) into words

return [] unless number[0,3].contain_positive_integers?

output = []

if number.tens == 1

output << TEENS[number.singles]

else

output << SINGLES[number.singles] unless number.singles.zero?

output << TENS[number.tens] if number.tens?

end

output << HUNDREDS << SINGLES[number.hundreds] if number.hundreds?

[output.reverse.join]

end

def self.unit(number, unit, exponent_or_range, places=3) # The amount of a unit, ranging over part of the number

list = if exponent_or_range.is_a?(Range) then number[exponent_or_range] else number[exponent_or_range,places] end

return [] unless list and list.contain_positive_integers?

[unit, to_swedish(list.reverse)]

end

end

if __FILE__ == $0

# Test run

puts Integer.to_swedish("")

puts 0.to_swedish

puts Integer.to_swedish("000foo0001")

puts Integer.to_swedish("1,024,908,267,229")

puts Integer.to_swedish("1.#{"0"*1_205}1")

end

outputs:

```
nil
noll
ett
en biljon tjugofyra miljarder niohundraåtta miljoner tvåhundrasextiosju tusen tvåhundratjugonio
en centiljard centiljarder ett
```