samedi 19 avril 2025

Braille Translator with Rebol and Red

I've always been impressed to see how blind children and adults are able to read Braille. It requires unparalleled tactile sensitivity and cognitive skills. In the early days, the braille cell consisted of 6 dots in a 2x3 matrix, representing 64 characters.  Later, this matrix became 2x4 with 8 dots, enabling 256 characters to be represented. 

[dots order 
1 4 
2 5 
3 6 
7 8
]

All these dots characters are now accessible in Unicode with values ranging from 10240 to 10495 (integer values). I've written a little ANSI->Braille->ANSI translator. The code is written in Rebol 3.19.0, but can be easily adapted to Red 0.6.6. There are some differences about the map! datatype.

The idea is simple. We build 2 dictionaries, one for ANSI->Braille coding and the second for Braille->ANSI coding. Maps are high performance dictionaries that associate keys with values and are very fast.

Classically, the first 32 ANSI codes do not represent characters, but escape codes used for communication with a terminal or printer. On the other hand, these 32 codes are used in Braille to facilitate document layout. 

This is the code:

#!/usr/local/bin/r3
Rebol [
]
;--generate ANSI and Braille codes
generateCodes: does [
i: 0 ;--we use all chars
codesA: #[] ;--a map object ANSI->Braille
codesB: #[] ;--a map object Braille->ANSI
while [i <= 255] [
idx: i + 10240 ;--for Braille code value
key: form to-char i ;--map key is ANSI value
value: form to-char idx ;--map value is Braille code
append codesA reduce [key value];--update map as string values
append codesB reduce [value key];--idem but reverse order key value
++ i
]
]

processString: func [
"Processes ANSI string or Braille string"
string [string!]
/ansi /braille
][
str: copy ""
;--for ansi use select/case, characters are case-sensitive
if ansi [foreach c string [append str select/case codesA form c]] 
if braille [foreach c string [append str select codesB form c]]
str

generateCodes
print-horizontal-line
print a: "Hello Fantastic Red and Rebol Worlds!"  
print-horizontal-line
print b: processString/ansi a
print-horizontal-line
print c: processString/braille b
print-horizontal-line

And the result: 


-------------------------------------------------------------------------------

Hello Fantastic Red and Rebol Worlds!

-------------------------------------------------------------------------------

⡈⡥⡬⡬⡯⠠⡆⡡⡮⡴⡡⡳⡴⡩⡣⠠⡒⡥⡤⠠⡡⡮⡤⠠⡒⡥⡢⡯⡬⠠⡗⡯⡲⡬⡤⡳⠡

-------------------------------------------------------------------------------

Hello Fantastic Red and Rebol Worlds!

-------------------------------------------------------------------------------


Thanks to the help of Oldes, we have a faster version that doesn't use the map! datatype.

encode-braille: function [
    "Process ANSI string and returns Braille string"
    text [string!]
][  
    out: copy ""
    foreach char text [
        if char <= 255 [char: char + 10240]
        append out char
    ]
    out
]
decode-braille: function [
    "Process string while decoding Braille's characters"
    text [string!]
][
    out: copy ""
    foreach char text [
        if all [char >= 10240 char <= 10495] [char: char - 10240]
        append out char
    ]
    out
]





Aucun commentaire:

Enregistrer un commentaire