Class: StringToNumber::ToNumber

Inherits:
Object
  • Object
show all
Defined in:
lib/string_to_number/to_number.rb

Overview

ToNumber class handles the conversion of French text to numbers It uses a complex recursive parsing algorithm to handle French number grammar

Constant Summary collapse

EXCEPTIONS =

EXCEPTIONS contains direct mappings from French words to their numeric values This includes:

  • Basic numbers 0-90

  • Feminine forms (“une” for “un”)

  • Regional variations (Belgian/Swiss French: “septante”, “huitante”, “nonante”)

  • Special cases for “quatre-vingt” variations with/without ‘s’

  • Compound numbers like “dix-sept”, “soixante-dix”

{
  'zéro' => 0,    # Zero with accent
  'zero' => 0,    # Zero without accent
  'un' => 1,      # Masculine "one"
  'une' => 1,     # Feminine "one"
  'deux' => 2,
  'trois' => 3,
  'quatre' => 4,
  'cinq' => 5,
  'six' => 6,
  'sept' => 7,
  'huit' => 8,
  'neuf' => 9,
  'dix' => 10,
  'onze' => 11,
  'douze' => 12,
  'treize' => 13,
  'quatorze' => 14,
  'quinze' => 15,
  'seize' => 16,
  'dix-sept' => 17,   # Compound: "ten-seven"
  'dix-huit' => 18,   # Compound: "ten-eight"
  'dix-neuf' => 19,   # Compound: "ten-nine"
  'vingt' => 20,
  'trente' => 30,
  'quarante' => 40,
  'cinquante' => 50,
  'soixante' => 60,
  'soixante-dix' => 70,     # Standard French: "sixty-ten"
  'septante' => 70,         # Belgian/Swiss French alternative
  'quatre-vingts' => 80,    # Standard French: "four-twenties" (plural)
  'quatre-vingt' => 80,     # Standard French: "four-twenty" (singular)
  'huitante' => 80,         # Swiss French alternative
  'quatre-vingt-dix' => 90, # Standard French: "four-twenty-ten"
  'quatre-vingts-dix' => 90,# Alternative with plural "vingts"
  'nonante' => 90           # Belgian/Swiss French alternative
}.freeze
POWERS_OF_TEN =

POWERS_OF_TEN maps French number words to their power of 10 exponents Used for multipliers like “cent” (10^2), “mille” (10^3), “million” (10^6) Includes both singular and plural forms for proper French grammar Uses French number scale where “billion” = 10^12 (not 10^9 as in English)

{
  'un' => 0,           # 10^0 = 1 (ones place)
  'dix' => 1,          # 10^1 = 10 (tens place)
  'cent' => 2,         # 10^2 = 100 (hundreds, singular)
  'cents' => 2,        # 10^2 = 100 (hundreds, plural)
  'mille' => 3,        # 10^3 = 1,000 (thousands, singular)
  'milles' => 3,       # 10^3 = 1,000 (thousands, plural)
  'million' => 6,      # 10^6 = 1,000,000 (millions, singular)
  'millions' => 6,     # 10^6 = 1,000,000 (millions, plural)
  'milliard' => 9,     # 10^9 = 1,000,000,000 (French billion, singular)
  'milliards' => 9,    # 10^9 = 1,000,000,000 (French billion, plural)
  'billion' => 12,     # 10^12 = 1,000,000,000,000 (French trillion, singular)
  'billions' => 12,    # 10^12 = 1,000,000,000,000 (French trillion, plural)
  'trillion' => 15,    # 10^15 (French quadrillion, singular)
  'trillions' => 15,   # 10^15 (French quadrillion, plural)
  # Extended list of large number names for completeness
  'quadrillion' => 15,
  'quintillion' => 18,
  'sextillion' => 21,
  'septillion' => 24,
  'octillion' => 27,
  'nonillion' => 30,
  'decillion' => 33,
  'undecillion' => 36,
  'duodecillion' => 39,
  'tredecillion' => 42,
  'quattuordecillion' => 45,
  'quindecillion' => 48,
  'sexdecillion' => 51,
  'septendecillion' => 54,
  'octodecillion' => 57,
  'novemdecillion' => 60,
  'vigintillion' => 63,
  'unvigintillion' => 66,
  'duovigintillion' => 69,
  'trevigintillion' => 72,
  'quattuorvigintillion' => 75,
  'quinvigintillion' => 78,
  'sexvigintillion' => 81,
  'septenvigintillion' => 84,
  'octovigintillion' => 87,
  'novemvigintillion' => 90,
  'trigintillion' => 93,
  'untrigintillion' => 96,
  'duotrigintillion' => 99,
  'googol' => 100      # Special case: 10^100
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sentence = '') ⇒ ToNumber

Initialize the ToNumber parser with a French sentence

Parameters:

  • sentence (String) (defaults to: '')

    The French text to be converted to numbers



108
109
110
111
112
113
114
115
116
117
# File 'lib/string_to_number/to_number.rb', line 108

def initialize(sentence = '')
  # Create regex pattern from POWERS_OF_TEN keys, excluding 'un' and 'dix'
  # which are handled differently in the parsing logic
  # Sort keys by length (longest first) to ensure longer matches are preferred
  # This prevents "cent" from matching before "cents" in "cinq cents"
  sorted_keys = POWERS_OF_TEN.keys.reject { |k| %w[un dix].include?(k) }.sort_by(&:length).reverse
  @keys = sorted_keys.join('|')  # Create regex alternation pattern
  # Normalize input to lowercase for case-insensitive matching
  @sentence = sentence&.downcase || ''
end

Instance Attribute Details

#keysObject

Returns the value of attribute keys.



7
8
9
# File 'lib/string_to_number/to_number.rb', line 7

def keys
  @keys
end

#sentenceObject

Returns the value of attribute sentence.



7
8
9
# File 'lib/string_to_number/to_number.rb', line 7

def sentence
  @sentence
end

Instance Method Details

#to_numberInteger

Main entry point to convert the French sentence to a number

Returns:

  • (Integer)

    The numeric value of the French text



121
122
123
# File 'lib/string_to_number/to_number.rb', line 121

def to_number
  extract(@sentence, keys)
end