Hebrew numbers

See Roman numerals for why the term 'numerals' would have been better fitting

Richard Suchenwirth - In the Hebrew system of writing numbers, as used in Israel, the letters of the alphabet are assigned numeric values (1 through 9, 10 through 90, 100 through 400). Higher numbers are expressed by addition (e.g. 900=400(+)400(+)100), and numbers above 1000 are written as high-order part (multiplied by 1000) 'tick' low-order part, where the above rules apply for both parts. (I assume this is repeated for numbers over 1 million). The following implementation takes a positive integer and returns the Hebrew number as a string of Unicodes. The exceptions that 15 is written as 6(+)9, 16 as 7(+)9 (plus more - see below!), are handled in the final string map command. Note that as zeroes are not expressed, I could use the first position (index 0) of each range list as a sort of "data-comment", which increases readability even if looking unusual for Tcl (or in fact, any language I'm aware of).

 proc iw'format i {
    if {$i >= 1000} {
        set res [iw'format [expr {$i%1000}]]´[iw'format [expr $i/1000]]
    } elseif {$i >= 400} {
        set res [iw'format [incr i -400]]\u05EA
    } else {
        set res ""
        foreach digit [lrevert [split $i ""]] range {
           {ones      \u05d0 \u05d1 \u05d2 \u05d3 \u05d4 \u05d5
                      \u05d6 \u05d7 \u05d8}
           {tens      \u05d9 \u05db \u05dc \u05de \u05e0 \u05e1
                      \u05e2 \u05e4 \u05e6}
           {hundreds  \u05e7 \u05e8 \u05e9 \u05EA}
        } {
            if {$digit!="" && $digit!=0} {
                append res [lindex $range $digit]
            }
        }
    }
    string map {
        \u05d4\u05d9 \u05d5\u05d8 # 15
        \u05d5\u05d9 \u05d6\u05d8 # 16
        \u05e8\u05e2 \u05e2\u05e8 # 270
        \u05e8\u05e2\u05d1 \u05d1\u05e2\u05e8 # 272
        \u05e8\u05e2\u05d4 \u05d4\u05e2\u05e8 # 275
        \u05e9\u05d3 \u05d3\u05e9 # 304
        \u05e9\u05d8 \u05d8\u05e9 # 309
    } $res ;# The above "# 15.. # 309" are not comments, but fake data!
 }

The numbers 270, 272, 275, 304, 309 are also ... not written in the normal pattern, because the normal pattern would spell a word with negative connotations. 270 and 275 would normally be spelled raysh ayin and raysh ayin hey. These spell ra and ra'ah, both of which mean "bad". 272 would normally be spelled resh ayin bet which spells ra'av meaning "famine." 304 would normally be spelled shin dalet which spells shaid meaning "demon." 309 would normally be spelled shin tet which spells shat meaning "to go astray." Since the normal way to write these numbers spells words with negative connotations, these numbers are written in reverse order. (Thanks to Ben Michelson!)

In the opposite direction, turning a numeric Hebrew string into an integer, the task was even easier as strict addition could be performed:

 proc iw'scan iwnum {
    set res 0
    set factor 1
    array set value {
        \u05d0 1 \u05d1 2 \u05d2 3 \u05d3 4 \u05d4 5 \u05d5 6
        \u05d6 7 \u05d7 8 \u05d8 9 \u05d9 10 \u05db 20 \u05dc 30
        \u05de 40 \u05e0 50 \u05e1 60 \u05e2 70 \u05e4 80 \u05e6 90
        \u05e7 100 \u05e8 200 \u05e9 300 \u05ea 400
    }
    foreach group [split $iwnum ´'] {
        set sum 0
        foreach char [split $group ""] {
            incr sum $value($char)
        }
        set res [expr {$res + $sum * $factor}]
        set factor [expr {$factor * 1000}]
    }
    set res
 }

Note that both procedures produce or read Hebrew so it "looks right" (from right to left) in Tk widgets, but in Unicode terms, this is wrong - strings in memory should always be in the correct logical direction, and the bi-directional rendering is a task of the final rendering software. As soon as Tk does correct "bidi" treatment, the output of iw'format or the group list of iw'scan will have to be reverted.


20 December, 2001 Note that I don't appear to have a command or procedure named [lrevert]. If, when you give us these generally quite impressive wizardries that you call "weekend projects", you also include references to the nonstandard functions you make use of, we (really me, a minority of one) would find it easier to be impressed.

RS Oops, sorry, here you go (also on Additional list functions):

 proc lrevert {L} {
        set res {}
        foreach i $L {set res [concat [list $i] $res]}
        set res
 }

WJP 2007-06-29 There isn't really a standard way to write numbers over 9,999. In ancient times, there just weren't many occasions on which it was necessary to write such large numbers, so there aren't a lot of examples and it appears that no single standard ever evolved. In post-Biblical times Jewish mathematicians, who did use larger numbers, wrote in Arabic and so used the Arabic numerals rather than the Hebrew ones, and in modern Hebrew the Western (that is, Indo-Arabic) numbers are used for just about everything except, sometimes, years in the Hebrew calendar. (I asked some Hebrew scholars about this recently when developing uninum.) Also, there are two ways of writing the hundreds greater than 400. The method described by Richard is the earlier one. The later variant adds letters for the higher hundreds as follows:

    500 U+05DA
    600 U+05DD
    700 U+05DF
    800 U+05E3
    900 U+05E5