""" EnglishTools by Csaba Urbaniczky, Chuck Esterbrook You can test with: cobra -test EnglishTools """ class EnglishTools shared def list(items as System.Collections.IList) as String """ Returns the English list form or a stream of objects. For example: [1, 2, 3] --> '1, 2 and 3' Any kind of objects may be passed in as they will be converted to strings via .toString. TODO: provide an overload that takes Object* TODO: decide on treatment of nil/null values in the list """ test cases = [ [[''], ''], [['one'], 'one'], [['a', 'b'], 'a and b'], [['a', 'b', 'c'], 'a, b and c'], [[1, 2, 3, 4], '1, 2, 3 and 4'], ] for input, output in cases print EnglishTools.list(input to System.Collections.IList) == output body words = for item in items get item.toString count = words.count if count == 0, return '' if count == 1, return words[0] sep = '' finalSep = ' and ' sb = StringBuilder() for i in count if i < count - 1 sb.append(sep) sep = ', ' else sb.append(finalSep) sb.append(words[i]) return sb.toString def numberToEnglish(n as int) as String """ Convert an integer, n, to a string in plain english. Can handle the entire range of integers. Change history: Rewritten version of a Ruby example from 'Learn to Program' v 1.0 2009-01-09 Csaba Urbaniczky: First version v 1.1 2009-01-10 Chuck Esterbrook: Second version, Cobra style! """ ensure result <> '' old n < 0 == result.startsWith('minus') # Cobra bug above: args should be implicitly old! test cases = [ [0, 'zero'], [5, 'five'], [15, 'fifteen'], [-10, 'minus ten'], [42, 'fourty-two'], [492, 'four hundred ninety-two'], [-1492, 'minus one thousand four hundred ninety-two'], [1341492, 'one million three hundred fourty-one thousand four hundred ninety-two'], [1341492123, 'one billion three hundred fourty-one million four hundred ninety-two thousand one hundred twenty-three'], ] for inputNumber, expectedEnglish in cases assert EnglishTools.numberToEnglish(inputNumber to int) == expectedEnglish to String body if n == 0, return 'zero' english = '' # Here is the the resulting text as the translation is added up # Take care of negative numbers if n < 0 english = 'minus ' n = n.abs # These are the binding numbers and the translated binding word bindingNumberLookup = [1_000_000_000 , 1000000, 1000, 100] bindingWordLookup = [' billion', ' million', ' thousand', ' hundred'] remainder = n # This is the remainder of the number that will appear as text to the right of a binding word # Go through the number for binding words and take care of the left part recursively for i in bindingNumberLookup.count n = remainder // bindingNumberLookup[i] # The left part to the binding word/number like ' hundred' remainder = remainder % bindingNumberLookup[i] # The right part of the binding word/number if n > 0 # Recursion to build up the left part of the number english += .numberToEnglish(n) + bindingWordLookup[i] if remainder > 0 english += ' ' # So we don't write as millionone.... # remainder is now the right part of the binding word and less than 100 - many spacail cases # Take care of 11 .. 19 teens specials since we can't write 'teenty-two' instead of twelve if remainder >= 11 and remainder <= 19 # Array used to look up english words for numbers, Since array is zero-based, fill '0:th place' with dummy value teenagersLookup = ['zero_never_used', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'] return english + teenagersLookup[remainder - 10] # Finished - return with this special case # Now 0 .. 10, 20 .. 99 in left to translate to plain english n = remainder // 10 # How many tens left, 0 or >=2 remainder %= 10 # Only single digits left now in remainder if n > 0 # The tens left tensPlaceLookup = ['zero_never_used', 'ten', 'twenty', 'thirty', 'fourty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'] english += tensPlaceLookup[n] if remainder > 0 english += '-' # so we don't write 'sixtyfour' # Take care of 0 .. 9 that is left to check if remainder > 0 # add string if it is larger than zero onesPlaceLookup = ['zero_never_used', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'onesPlaceLookupbug'] return english + onesPlaceLookup[remainder] else return english def plural(word as String) as String """ Returns the plural form of a word. """ ensure (word == '') == (result == '') test cases = [ ['', ''], ['cat', 'cats'], ['mass', 'masses'], ['5', '5s'], ] for input, output in cases assert EnglishTools.plural(input) == output body # TODO: Needs a lot of work. This could be helpful: # http://www.google.com/codesearch?hl=en&lr=&q=plural&sbtn=Search if word == '', return word for c in 'sxz' if word.endsWith(c.toString) return word + 'es' return word + 's'