How many letters in this word?

12

1

Inspired by Project Euler #17, this is your challenge. Write a full program or function that takes a number as input, then print or return how many letters it would take to count up to and including that number in English (starting at one). You do not include spaces, commas, or hyphens, but you should include the word and. For example. 342 is spelled: Three Hundred and Forty-Two. This is 23 letters long.

Your input will be a positive integer. You do not have to handle invalid inputs. Built-ins or libraries that convert numbers to English are not allowed.

Here are all of the rules for how to spell numbers. (Note: I realize that some people use a different set of rules for how to spell numbers. This will just be the official rules for the purpose of this challenge)

1 to 20

one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty

21 to 99

Join these:

Twenty, thirty, forty, fifty, sixty, seventy, eighty, ninety

to these:

-one, -two, -three, -four, -five, -six, -seven, -eight, -nine,

Note that four has a u but forty does not!

Examples:

53: Fifty-three
60: sixty
72: seventy-two
99: ninety-nine

100 to 999

Write out how many hundreds (one hundred, two hundred, three hundred, etc.), an "and", and the rest of the number as above. The and does count towards your letter score.

Examples:

101: One hundred and one
116: One hundred and sixteen
144: One hundred and forty-four
212: Two hundred and twelve
621: Six Hundred and twenty-one

1,000 to 999,999

Write how many thousands (one thousand, two thousand, etc.), a comma, then the rest of the number as above. Note that if you have no hundreds, you still need the and.

Examples:

1,101: One thousand, one hundred and one
15,016: Fifteen thousand and sixteen
362,928: Three hundred and sixty-two thousand, nine hundred and twenty-eight

Millions

Write out how many millions, then the rest of the number as above. Note that "A million" is 6 zeroes "1,000,000".

Examples:

191,232,891: One hundred and ninety-one million, two hundred and thirty-two thousand, eight hundred and ninety-one
1,006,101: One million, six thousand, one hundred and one

The same rule applies to billions, trillions, quadrillions and above, but for the purpose of this challenge, you don't have to handle any number above 999,999,999 (Nine Hundred and ninety-nine million, nine-hundred and ninety-nine thousand, nine hundred and ninety-nine.)

Python solver

Here is a short python script to verify answers:

import en 

def get_letter_num(s):
    count = 0
    for c in s:
        if c.isalpha():
            count += 1
    return count

number = input()
count = 0
for i in xrange(1, number + 1):
    count += get_letter_num(en.number.spoken(i))

print count

Note that this usesthe NodeBox linguistics library to convert numbers to English. (yes, I just broke my own rule, but this isn't a competing answer) This is freely available here.

Sample I/O

7: 27
19: 106
72: 583
108: 1000
1337: 31,131
1234567: 63,448,174

James

Posted 2016-02-19T17:58:59.910

Reputation: 54 537

1Why is it One hundred and one, but then One million, six thousand, one hundred one without the and? – Geobits – 2016-02-19T18:18:04.097

@Geobits Typo. Also You do not include spaces, commas, or hyphens, but you should include the word "and". – James – 2016-02-19T18:27:35.283

1Related and more related. – Zgarb – 2016-02-19T18:32:57.517

Shouldn't 15016 be fifteen thousand sixteen according to "the rest of the number as above"? – FryAmTheEggman – 2016-02-19T18:46:22.913

I can't find anything wrong with what I am doing, but I seem to get 31,128 for 1337. It seems odd to be off by exactly three, could you check that the rules are all correct and that that is the correct output? I get the same answer for 108. – FryAmTheEggman – 2016-02-19T23:53:26.293

@FryAmTheEggman I am definitely getting 31,131. How about post it as an answer with a disclaimer, and I'll look at it and see if I can spot the difference. – James – 2016-02-19T23:55:52.683

Invalid answers are Bad™ so here is a link

– FryAmTheEggman – 2016-02-19T23:58:18.900

Oh, I didn't think of this before, I had a program that is too long to fit in a comment that englishifies the range of numbers for debugging. I made a paste of the results for 1337 if that helps.

– FryAmTheEggman – 2016-02-20T00:14:32.037

@FryAmTheEggman 1100 -> one thousand and one hundred. – TheNumberOne – 2016-02-24T13:52:50.360

How does that scale to 1200 then? Or 10100? I don't see a rule that would indicate one hundred is a special case, I'm not sure how to handle it. – FryAmTheEggman – 2016-02-24T14:05:58.173

1@FryAmTheEggman Using his python script, 1100 -> one thousand and one hundred; 1200 -> one thousand two hundred, 1000100 -> one million and one hundred, 1000200 -> one millian two hundred. I think either A) DJ McGoathem should address the 1100 and 1000100 special cases in his question, or B) correct his test cases – TheNumberOne – 2016-02-24T18:00:47.593

4Why the "and"? Proper names for numbers never use it: 123 = "one hundred twenty-three" – ricdesi – 2016-02-24T20:42:25.710

1

@ricdesi I agree. Related. People count "one thousand one, one thousand two, ...", without the ands.

– mbomb007 – 2016-02-24T21:49:03.020

Answers

1

Python 2, 266 259 236 229 228 bytes

This works for all inputs below one billion. This works for all test cases.

def l(n):b=[6,3,2][(n<1000)+(n<10**6)];c=10**b;return int("0335443554"[n%10])+int("0366555766"[n/10])+(n-10in[4,6,7,9])if n<100else l(n/c)+(l(n%c)or-3*(b<3))+7+(b<6)+2*(b<3)+3*(b>2)*(0<n%c<101)
print sum(map(l,range(input()+1)))

To modify it to fit the question as stated (e.g. don't treat numbers ending with 100 special) simply replace the number 101 at the end of the first line with 100.

Explanation:

def l(n):
    b=[6, 3, 2][(n < 1000) + (n < 10**6)] # b = 2 if n < 1000 else 3 if n < 1000000 else 6
    c=10**b
    return (                            # Parenthesis added for readability.
            int("0335443554"[n % 10]) + # Compute length of last digit. one -> 3, seven -> 5, etc.
            int("0366555766"[n / 10]) + # Compute length of second to last digit. ten -> 3, eighty -> 6, etc.
            (n - 10 in[4, 6, 7, 9])     # Add one to length if the number is 14, 16, 17, or 19.

            if n < 100 else             # Use above procedure if the number is under 100.
                                        # If otherwise, use below procedure.

            l(n / c) +                  # Compute length of the top portion of number.
                (l(n % c) or            # Compute length of bottom portion of number.
                -3 * (b < 3)) +         # If the number < 1000 and is a multiple of 100,
                                        # subtract 3 from the length because of missing and.
            7 +                         # Add 7 to the length for "million"
            (b < 6) +                   # Add 8 to the length for "thousand"
            2 * (b < 3) +               # Add 10 to the length for "hundred and"
                3 *                     # Add 3 to the length for another "and"
                (b > 2) *               # if the number >= 1000
                (0 < n % c < 101)       # and the bottom portion > 0 and <= 100
    )
print sum(map(l,range(input()+1)))      # For the reader to figure out.

TheNumberOne

Posted 2016-02-19T17:58:59.910

Reputation: 10 855