Translating the Cardinal Numerals to Words

Can you guys bring on your magic to help me translate digits into words.

Here is what I want to do:
I want a system that translates digit numbers in a long text into a specific format.

If the text contain a number like 123, I want this to appear as [123]{cardinal}(one hundred twenty three)

The numbers could range from 1 to millions.

Here is a small sample

1: [1]{cardinal}(one)
2: [2]{cardinal}(two)
4: [4]{cardinal}(four)
13: [13]{cardinal}(tens three)
14: [14]{cardinal}(tens four)
24: [24]{cardinal}(twenty four)
56: [56]{cardinal}(fifty six)
123: [123]{cardinal}(one hundred twenty three)
212: [212]{cardinal}(two hundred tens two)
1235: [1235]{cardinal}(one thousand two hundred thirty five)

Note that, I am using tens one in stead of eleven because the system needs to be consistent just like twenty one.

here is a sample text in the original format:
I had 25 friends in the school.

Converted form:
I had [25]{cardinal}(twenty five) friends in the school.

Here is what I have tried so far. I was successful up to 100; then failed on teh 3 digit numbers.
NumberTranslate Macros.kmmacros (87.6 KB)

The strategy is to first translate the core ditits (1-9), and then, reuse it to higher number translations. Even if I have the concept on how to do it, I failed to put into practice. Can you guys help me please?

Python and Perl have libraries for doing this (except for how you want numbers between 10 and 20), and I imagine there are similar libraries for other languages. I suggest you study their code and adapt it to your purposes.


Thank you for the reply. I don't think I can use these libraries because they don't support the language I am finally interested in.

I am pretty sure this can be done within KM. I just struggled a bit with the regex that needs to be applied on the sub-strings. I am sure guys such as @ComplexPoint & @ccstone can easily nail this.

I second @drdrang's advice and take the opportunity to point out one of the sweetest things about Keyboard Maestro is that it's Execute a Shell Script and variants allow you to mix and match code from various languages in the same macro.

But if you want to roll your own, I'd suggest reversing the string, deleting any commas or other punctuation and working your way left to right through the numerals as an array of characters.


Ourobouros ?

Get a macOS speaking voice to pronounce the numbers, and redirect the stream to a voice control transcription with a numbers as words option ?

(That is the least efficient and most interesting approach that comes immediately to mind :slight_smile: )

What's the context here ? It seems a slightly unusual transcription ...

I love your outside the box thinking. In macOS Monterey the voice transcription is very good and that should work. I recommend improving the quality and accuracy using Audio Hijack which can pipe the output from macOS directly into Monterey Voice Transcription so that there are no speakers or microphone involved.

But using the method she wants to use, it should be a fun assignment. Actually, it sounds like a school assignment.

I honestly don't think the voice transcription is an option because the numbers I want to transcribe are interspersed in a large body of text.

  • Copy the text-->find the number-->convert them -->paste

That was what i was planning to do.

After all, my problems seems to melt down to one core issue:
how to run a macro on a subpart of a variable/clipboard.

I have almost developed a system. What made me stuck is my inability to run a macro on part of variable (the last digit, of a 2 digit number, for example).

I totally accept that you reject transcription. That's fine.

You didn't really mention though, that you needed to "find" the numbers in a larger body of text in a document. Your sample macro didn't seem to indicate this, and the sample data that you showed in your original post seemed to show one number per line. Perhaps if you had given a real world example it would have been clearer and the solutions offered would be more likely to be correct.

I think it's a fun assignment. I think it can be done with a single, short KM macro, or two macros at most, and perhaps the simplest solution will include a recursive macro. I'm willing to help, but I am required to get some food right now.

1 Like

A sample text would look like the following (from Wikipedia)

Estimates of the population of the world at the time agriculture emerged in around 10,000 BC have ranged between 1 million and 15 million. Even earlier, genetic evidence suggests humans may have gone through a population bottleneck of between 1,000 and 10,000 people about 70,000 BC, according to the Toba catastrophe theory. By contrast, it is estimated that around 50–60 million people lived in the combined eastern and western Roman Empire in the 4th century AD.

The Plague of Justinian, which first emerged during the reign of the Roman emperor Justinian, caused Europe's population to drop by around 50% between the 6th and 8th centuries AD. The population of Europe was more than 70 million in 1340. The Black Death pandemic of the 14th century may have reduced the world's population from an estimated 450 million in 1340 to between 350 and 375 million in 1400; it took 200 years for population figures to recover. The population of China decreased from 123 million in 1200 to 65 million in 1393, presumably from a combination of Mongol invasions, famine, and plague.

Starting in AD 2, the Han Dynasty of ancient China kept consistent family registers in order to properly assess the poll taxes and labor service duties of each household. In that year, the population of Western Han was recorded as 57,671 individuals in 12 million households, decreasing to 47 million individuals in 9 million households by AD 146, towards the End of the Han Dynasty. At the founding of the Ming Dynasty in 1368, China's population was reported to be close to 60 million; toward the end of the dynasty in 1644, it may have approached 150 million. England's population reached an estimated 5.6 million in 1650, up from an estimated 2.6 million in 1500. New crops that were brought to Asia and Europe from the Americas by Portuguese and Spanish colonists in the 16th century are believed to have contributed to population growth. Since their introduction to Africa by Portuguese traders in the 16th century, maize and cassava have similarly replaced traditional African crops as the most important staple food crops grown on the continent.

The pre-Columbian population of the Americas is uncertain; historian David Henige called it "the most unanswerable question in the world." By the end of the 20th century, scholarly consensus favored an estimate of roughly 55 million people, but numbers from various sources have ranged from 10 million to 100 million. Encounters between European explorers and populations in the rest of the world often introduced local epidemics of extraordinary virulence. According to the most extreme scholarly claims, as many as 90% of the Native American population of the New World died of Old World diseases such as smallpox, measles, and influenza. Over the centuries, the Europeans had developed high degrees of immunity to these diseases, while the indigenous peoples had no such immunity.

Aha! So you want the macro to handle commas! You didn't mention that in your first post or in your examples, which had no commas for numbers above 1000. You also didn't mention what you want done with fraction numbers, and your example text includes fractional numbers. I'm also unclear if you want "20th" to come back as "twenty th" or something else.

Whoever writes your code, whether it's you or someone else, needs to know what to do in these cases. Your problem needs to be understood accurately before it can be coded accurately. It seems to be slightly harder now that you are showing more context.

I presume that the text you want to process is just plain text, not formatted text, and that it is available in either a clipboard or a file.

  • Yes, it is a plain text. I am not really worried about the comma; I can remove with simple macro. The ordinals are not the interest as well.
  • as to 20th, I want it so that 20 will be processed as is.

You didn't indicate what you wanted to do with fractional numbers like "2.6" which appear in the text.

Maybe that's not the right approach. I won't be bound by your approach. I'm only bound by the stated problem.

EDIT: Your original post did not put limits on what we could use to solve your problem. Later on, you said you didn't want to use Perl or Python. That's fine. But you didn't put any other limitations on how to achieve your goal. Since I'm lazy, I always choose the easiest way. I found a single command that solves half of your problem (the conversion from a number to a word):

curl -s | tr '<>' '\n\n' | grep -A 2 txt2 | head -n 2 | tail -n 1 | sed -f ~/data/teens.txt

(The number 19 would be modified to a KM variable if you wanted to use KM to solve this.) This single command does the work by getting a remote website to do all the work for us, except for the work of the conversion of your teen numbers, and the "sed command" in the above statement solves that because of this file (~/data/teens.txt) on my system: (older versions of macOS may not support this, and you didn't say which version of macOS you have.)

s/eleven/ten ones/
s/twelve/ten twos/
s/thirteen/ten threes/
s/fourteen/ten fours/
s/fifteen/ten fives/
s/sixteen/ten sixes/
s/seventeen/ten sevens/
s/eighteen/ten eights/
s/nineteen/ten nines/

I have a feeling you will reject this solution for some reason that you haven't yet provided, but I found it rewarding to work on. So, it was fun for me. And it meets all your original requirements in your first post (well, at least the part about converting numbers to words.)

HOWEVER there is a problem with the curl statement above: when I run it from KM's Shell action, it always returns the number "one" from the website. I think that's because the curl statement returns data too fast when run inside KM (not a problem from the Shell.) So I switched to a different website to get it to work in KM, but doing that created an extra ten KM actions. Since you probably don't want this approach, I won't post that macro.

Thank you for the reply; and for thinking about it dear @Sleepy
Can you post the macro please?

The problem is more complex than I thought.

Can you guys just help me with this?
12_13_21 at 09.35.44AM

I want to run the macro"2:0-9" only on the second digit ($2). Is there any way to do that, using tools such as subroutine or sth like that?

The reason why I didn't accept these solutions is because they are specific to specific languages. I was hopping to find a solution that would work for languages that are not supported by these tools:

If the solution was done with regex, in KM, I won't have to worry about the languages: what I need is just convert the words from one language to another. Here is an example I want to process from an African language: (note that all these languages use the Arabic cardinals).

የህወሓት ኃይሎች በአፋር ክልል ውስጥ በቆዩባቸው ጊዜያት ከ60 በላይ የጤና ተቋማት ላይ ጉዳት ማድረሳቸውን የክልሉ የጤና ቢሮ ኃላፊ አቶ ያሲን ሐቢብ ለቢቢሲ ገለጹ።
"ሙሉ በሙሉ በሚባል ደረጃ አንድ ሆስፒታል እና ወደ 62 የጤና ተቋማትም ወድመዋል" ሲሉ የተከሰተውን አስረድተዋል።
ጉዳት የደረሰው በ17 የጤና ጣቢያዎች፣ በአንድ ሆስፒታል እና በ42 የጤና ኬላዎች ላይ እንደሆነ እና ጉዳቱም የተቋሙ ግንባታ መሰባበር እና የመድኃኒት ዘረፋን እንሚጨምር አቶ ያሲን ተናግረዋል።
በክልሉ ያለውን የጤና ሥርዓት "አንኮታኩተው ነው የሄዱት።

This is a BBC news written in an Ethiopian language. There are cardinals there. I want to process them. The tools mentioned above don't support this language: and if I want to include the language, it will take me days to learn their internal mechanisms of the scripts (let alone: my zero knowledge of Python or Perl).

If I have a system worked for English within the KM, I would simply translate each word from English to the Ethiopian or Greek or Afrikaans, for that matter.

But, it seems like the problem is more challenging than I first thought it to be. I felt that I am almost there: but have been stuck on how to run macros on subpart of a given number. May be the new subroutine is the solution. But, I don't understand it yet.

That makes sense. Thanks for explaining the bigger picture.

When you said that above, way back in post #2, I thought you were talking about computer languages, not spoken languages, because you said "languages" while talking about Python and Perl. I had no idea you were talking about foreign human languages. You never gave an example of a foreign language until now, so we had a misunderstanding. I hope you can see why I misunderstood you. This is why before/after examples are so helpful.

But now that I understand you, I think you are wrong about Python and Perl, for two reasons. Firstly, you don't need to learn the language to be able to run utilities made in those languages. Secondly, the utilities in those languages are almost certainly not specific to English. In fact, they won't be language dependent at all because they will probably accept only number strings as their input and return the word strings. (Both of which are referred to as "cardinal numbers," by the way.) The language would be irrelevant.

P.S. Are you aware that 12 major languages read from right to left and the order of the words that result from this macro would need to be displayed from right to left?

Are you saying you want a macro that does the conversion by translating it on an external website? As far as I know, the example above (the curl command) works 100% correctly. I can probably make it work for you in a KM action if you want. Is that what you want? It will convert any numeric string that you pass it, and it will return the word-string in its place. As I said, that's half the problem. The other half is writing the code that fetches the numeric strings from your file or clipboard. Are you able to handle that half of the problem, or do you need help with that? Did you test the curl statement above in your Terminal to confirm that it does all the work accurately and fast? You open the Terminal app, create the file called teens.txt, and then run the curl statement from the Terminal window. Are you able to do that to see how fantastically it works?

Sorry for the confusion i caused. Yes, I was talking about human languages.

The Python script has a list of languages supported in the github repository.
I also see people making requests to add languages: (here is a request for Persian)

The same with the Perl: " Lingua::EN::Nums2Words" is there for a reason, I think.

  • As to the languages that are written from the right to left, yes, that is another challenge. But, for now, they are not in my radar.

I'd love to help, but I don't know what that means. If it means can you pass the second digit to a macro, yes you can. But I'm not sure that's what you mean. And I don't know what the word "sth" means in your sentence.

I'm guessing that you want the macro to return a value into the second digit of the system clipboard, even though you didn't say that. If so, you certainly cannot do it that way. For one thing, macros are not functions. Users cannot create functions in KM. If you have the latest version of KM, it now supports subroutines that can return a value, but not as a function does. For another thing, you can't use the name of the macro to perform any parameter passing, as you seem to be trying to do.

Also, in my opinion, you should never perform long term processing of data inside the clipboard, because the clipboard can change unexpectedly, such as when you are editing a macro. Don't make your life difficult, and that means move your data into a variable and work with it there. Such a small thing can save you much grief.

This problem might be complex for some people, but it's not complex for others. But some of us are probably thinking, "Why not just use code that already exists instead of re-inventing the wheel?" I love this kind of problem, so I spent half the day coming up with ideas for you, some of which I haven't even explained yet. I even encoded a solution in KM using the kind of approach you want to use, but it's only 75% finished. I'll post it right after this post, because this post is already too long.

I didn't completely finish my macro which does the job that you want done using the methodology that you think is the best, and I'm posting a screenshot of it below. Since it doesn't work, I'm posting only an image. But it might help you because it's a good first shot at this problem. It might give you an idea of some good techniques to use in solving this sort of problem, for example, the way I'm handling the triples of digits, or the way I add a couple of leading zeros so that the number of digits is always a multiple of 3. Maybe you want to work with it yourself, or maybe you just want to wait for me to finish it.


1 Like

This is completely beyond my capabilities. Thank you for being patient with me, for my poorly worded questions and issues, and for spending your time to help me.

I will be looking forward to it.