The      Four is ...      sequence is based on the counting of the number of
letters in the words of the (never─ending) sentence:

  Four is the number of letters in the first word of this sentence, two in the second,
  three in the third, six in the fourth, two in the fifth, seven in the sixth, ··· 



Definitions and directives

   English is to be used in spelling numbers.
   Letters   are defined as the upper─ and lowercase letters in the Latin alphabet   (A──►Z   and   a──►z).
   Commas are not counted,   nor are hyphens (dashes or minus signs).
   twenty─three   has eleven letters.
   twenty─three   is considered one word   (which is hyphenated).
   no    and    words are to be used when spelling a (English) word for a number.
   The American version of numbers will be used here in this task   (as opposed to the British version).
         2,000,000,000   is two billion,   not   two milliard.



Task

   Write a driver (invoking routine) and a function (subroutine/routine···) that returns the sequence (for any positive integer) of the number of letters in the first   N   words in the never─ending sentence.   For instance, the portion of the never─ending sentence shown above (2nd sentence of this task's preamble),   the sequence would be:
         4  2  3  6  2  7

   Only construct as much as is needed for the never─ending sentence.
   Write a driver (invoking routine) to show the number of letters in the   Nth   word,   as well as   showing the   Nth   word itself.
   After each test case, show the total number of characters   (including blanks, commas, and punctuation)   of the sentence that was constructed.
   Show all output here.


Test cases

 Display the first  201  numbers in the sequence   (and the total number of characters in the sentence).
 Display the number of letters  (and the word itself)  of the       1,000th  word.
 Display the number of letters  (and the word itself)  of the      10,000th  word.
 Display the number of letters  (and the word itself)  of the     100,000th  word.
 Display the number of letters  (and the word itself)  of the   1,000,000th  word.
 Display the number of letters  (and the word itself)  of the  10,000,000th  word  (optional).



Related tasks

   Four is magic
   Look-and-say sequence
   Number names
   Self-describing numbers
   Self-referential sequence
   Spelling of ordinal numbers


Also see

   See the OEIS sequence  A72425 "Four is the number of letters...".
   See the OEIS sequence  A72424 "Five's the number of letters..."


using DataStructures # for deque
 
const seed = "Four is the number of letters in the first word of this sentence, "
const (word2, word3) = ("in", "the")
 
lettercount(w) = length(w) -  length(collect(eachmatch(r"-", w)))
splits(txt) = [x.match for x in eachmatch(r"[\w\-]+", txt)]
todq(sentence) = (d = Deque{String}(); map(x->push!(d, x), splits(sentence)[2:end]); d)
 
struct CountLetters
    seedsentence::String
    words::Deque{String}
    commasafter::Vector{Int}
    CountLetters(s) = new(s, todq(s), [13])
    CountLetters() = CountLetters(seed)
end
 
function Base.iterate(iter::CountLetters, state = (1, 5, ""))
    if length(iter.words) < 1
        return nothing
    end
    returnword = popfirst!(iter.words)
    nextwordindex = state[1] + 1
    wordlen = lettercount(returnword)
    wordvec = vcat(num2text(wordlen), word2, word3, splits(numtext2ordinal(num2text(nextwordindex))))
    map(x -> push!(iter.words, x), wordvec) 
    push!(iter.commasafter, length(iter.words))
    added = length(returnword) + (nextwordindex in iter.commasafter ? 2 : 1)
    (wordlen, (nextwordindex, state[2] + added, returnword))
end
 
Base.eltype(iter::CountLetters) = Int
 
function firstN(n = 201)
    countlet = CountLetters()
    print("It is interesting how identical lengths align with 20 columns.\n   1:   4")
    iter_result = iterate(countlet)
    itercount = 2
    while iter_result != nothing
        (wlen, state) = iter_result
        print(lpad(string(wlen), 4))
        if itercount % 20 == 0
            print("\n", lpad(itercount+1, 4), ":")
        elseif itercount >= n
            break
        end
        iter_result = iterate(countlet, state)
        itercount += 1
    end
    println()
end
 
function sumwords(iterations)
    countlet = CountLetters()
    iter_result = iterate(countlet)
    itercount = 2
    while iter_result != nothing
        (wlen, state) = iter_result
        if itercount == iterations
            return state
        end
        iter_result = iterate(countlet, state)
        itercount += 1
    end
    throw("Iteration failed on \"Four is the number\" task.")
end
 
firstN()
 
for n in [2202, 1000, 10000, 100000, 1000000, 10000000]
    (itercount, totalletters, lastword) = sumwords(n)
    println("$n words -> $itercount iterations, $totalletters letters total, ",
            "last word \"$lastword\" with $(length(lastword)) letters.")
end