Extended Straddling Checkerboard
An extended Straddling Checkerboard, is like the regular Straddling checkerboard, but allows word dictionaries and arbitrary functional codes such as FIGURE, where you can specify a number literally.
- Task
Implement encoding and decoding of a message using the extended straddling checkerboard, CT-37w, as described in the reference below.
You may switch the codes for F/L (99) and SUPP (98) to help differentiate the code for '9' from that of '999' and, if you do that, then digits only needed to be doubled rather than tripled. So we would then have the following checkerboard:
A E I N O T CODE 0 1 2 3 4 5 6 B C D F G H J K L M 70 71 72 73 74 75 76 77 78 79 P Q R S U V W X Y Z 80 81 82 83 84 85 86 87 88 89 SPC (.) ACK REQ MSG RV GRD SND F/L SUP 90 91 92 93 94 95 96 97 98 99 0 1 2 3 4 5 6 7 8 9 00 11 22 33 44 55 66 77 88 99
There is no need to create a word dictionary for CODE (6). It suffices to just include CODE followed by some 3 digit number in the message to be encoded.
Test your solution by encoding and decoding the message:
'Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March'
- Related task
- Reference
-
- Cipher Machines web page on Checkerboards: Checkerboards
FreeBASIC
Const As String efigs = "0123456789"
Const As String spc_ = "90"
Const As String dot = "91"
Const As String fsl = "98"
Const As String row1 = "AEINOT"
Const As String row2 = "BCDFGHJKLM"
Const As String row3 = "PQRSUVWXYZ"
Const As String row4 = " ."
Dim Shared As String emapKeys(Len(row1) + Len(row2) + Len(row3) + Len(row4))
Dim Shared As String emapValues(Len(row1) + Len(row2) + Len(row3) + Len(row4))
Dim As Integer i, index = 0
For i = 1 To Len(row1)
emapKeys(index) = Mid(row1, i, 1)
emapValues(index) = Str(i - 1)
index += 1
Next
For i = 1 To Len(row2)
emapKeys(index) = Mid(row2, i, 1)
emapValues(index) = Str(70 + i - 1)
index += 1
Next
For i = 1 To Len(row3)
emapKeys(index) = Mid(row3, i, 1)
emapValues(index) = Str(80 + i - 1)
index += 1
Next
For i = 1 To Len(row4)
emapKeys(index) = Mid(row4, i, 1)
emapValues(index) = Str(90 + i - 1)
index += 1
Next
Function getEmapValue(Byval key As String) As String
For i As Integer = 0 To Ubound(emapKeys)
If emapKeys(i) = key Then Return emapValues(i)
Next
Return ""
End Function
Type Map
Dim As String keys(100)
Dim As String values(100)
End Type
Dim Shared As Map ewords
ewords.keys(0) = "ACK" : ewords.values(0) = "92"
ewords.keys(1) = "REQ" : ewords.values(1) = "93"
ewords.keys(2) = "MSG" : ewords.values(2) = "94"
ewords.keys(3) = "RV" : ewords.values(3) = "95"
ewords.keys(4) = "GRID" : ewords.values(4) = "96"
ewords.keys(5) = "SEND" : ewords.values(5) = "97"
ewords.keys(6) = "SUPP" : ewords.values(6) = "99"
Function getValue(Byval key As String, Byval map As Map) As String
For i As Integer = 0 To Ubound(map.keys)
If map.keys(i) = key Then Return map.values(i)
Next
Return ""
End Function
Dim Shared As String*6 drow1 = "012345"
Dim Shared As String dmapKeys(Len(drow1))
Dim Shared As String dmapValues(Len(drow1))
For i = 1 To Len(drow1)
dmapKeys(i - 1) = Mid(drow1, i, 1)
dmapValues(i - 1) = emapKeys(i - 1)
Next
Dim Shared As Map dwords
dwords.keys(0) = "92" : dwords.values(0) = "ACK"
dwords.keys(1) = "93" : dwords.values(1) = "REQ"
dwords.keys(2) = "94" : dwords.values(2) = "MSG"
dwords.keys(3) = "95" : dwords.values(3) = "RV"
dwords.keys(4) = "96" : dwords.values(4) = "GRID"
dwords.keys(5) = "97" : dwords.values(5) = "SEND"
dwords.keys(6) = "99" : dwords.values(6) = "SUPP"
Function getDmapValue(Byval key As String) As String
For i As Integer = 0 To Ubound(dmapKeys)
If dmapKeys(i) = key Then Return dmapValues(i)
Next
Return ""
End Function
Function keyExists(Byval key As String, keys() As String) As Boolean
For i As Integer = 0 To Ubound(keys)
If keys(i) = key Then Return True
Next
Return False
End Function
Function encode(Byval s As String) As String
s = Ucase(s)
Dim As String res = ""
Dim As String word = ""
Dim As Integer wc = Len(s)
For i As Integer = 1 To wc
Dim As String c = Mid(s, i, 1)
If c <> " " And i <> wc Then
word &= c
Else
If i = wc Then word &= c
Dim As String add_ = ""
If keyExists(word, ewords.keys()) Then
add_ = getValue(word, ewords)
Elseif keyExists(Left(word, Len(word) - 1), ewords.keys()) And Right(word, 1) = "." Then
add_ = getValue(Left(word, Len(word) - 1), ewords) & dot
Elseif Left(word, 4) = "CODE" Then
add_ = "6" & Mid(word, 5)
Else
Dim As Boolean figs = False
For j As Integer = 1 To Len(word)
Dim As String c = Mid(word, j, 1)
If Instr(efigs, c) > 0 Then
If figs Then
add_ &= c & c
Else
figs = True
add_ &= fsl & c & c
End If
Else
Dim As String ec = getEmapValue(c)
If ec = "" Then
Print "Message contains unrecognized character '" + c + "'."
End
End If
If figs Then
add_ &= fsl & ec
figs = False
Else
add_ &= ec
End If
End If
Next
If figs And i < wc Then add_ &= fsl
End If
res &= add_
If i < wc Then res &= spc_
word = ""
End If
Next
Return res
End Function
Function decode(Byval s As String) As String
Dim As String res = ""
Dim As Integer sc = Len(s)
Dim As Integer figs = 0
Dim As Integer i = 1
While i <= sc
Dim As String c = Mid(s, i, 1)
Dim As String twoChars = Mid(s, i, 2)
If figs Then
If twoChars = fsl Then
figs = 0
Else
res &= c
End If
i += 2
Elseif Instr(drow1, c) > 0 Then
res &= emapKeys(Val(c))
i += 1
Elseif c = "6" Then
res &= "CODE" & Mid(s, i + 1, 3)
i += 4
Elseif c = "7" Or c = "8" Then
Dim As String mapKey = twoChars
For j As Integer = 0 To Ubound(emapKeys)
If emapValues(j) = mapKey Then
res &= emapKeys(j)
Exit For
End If
Next
i += 2
Elseif c = "9" Then
Dim As String d = Mid(s, i + 1, 1)
If d = "0" Then
res &= " "
Elseif d = "1" Then
res &= "."
Elseif d = "8" Then
figs = Not figs
Else
res &= getValue(c & d, dwords)
End If
i += 2
End If
Wend
Return res
End Function
Dim As String msg = "Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March"
Print !"Message:\n"; msg
Dim As String enc = encode(msg)
Print !"\nEncoded:\n"; enc
Dim As String dec = decode(enc)
Print !"\nDecoded:\n"; dec
Sleep
- Output:
Same as Wren entry.
jq
Adapted from Wren
Works with jq, the C implementation of jq
Works with gojq, the Go implementation of jq
Works with jaq, the Rust implementation of jq
### Generic utility
# Emit a stream of the constituent codepoints:
def chars: explode[] | [.] | implode;
### The checkerboard
def efigs: "0123456789";
def drow1: "012345";
def checkerboard:
def row1: "AEINOT";
def row2: "BCDFGHJKLM";
def row3: "PQRSUVWXYZ";
def row4: " .";
{ ewords: {
"SPC": "90", "DOT": "91",
"ACK": "92", "REQ": "93", "MSG": "94", "RV": "95",
"GRID": "96", "SEND": "97", "FSL": "98", "SUPP": "99"
},
emap: {},
dmap: {},
dwords:{}
}
| reduce range(0; row1|length) as $i (.; .emap[row1[$i:$i+1]] = ($i|tostring) )
| reduce range(0; row2|length) as $i (.; .emap[row2[$i:$i+1]] = ((70 + $i)|tostring))
| reduce range(0; row3|length) as $i (.; .emap[row3[$i:$i+1]] = ((80 + $i)|tostring))
| reduce range(0; row4|length) as $i (.; .emap[row4[$i:$i+1]] = ((90 + $i)|tostring))
| reduce (.emap|keys[]) as $k (.; .dmap[.emap[$k]] = $k)
| reduce (.ewords|keys[]) as $k (.; .dwords[.ewords[$k]] = $k) ;
def encode:
(ascii_upcase|split(" ")) as $words
| ($words|length) as $wc
| checkerboard
| .res = ""
| reduce range(0; $wc) as $i (.;
$words[$i] as $word
| .add = ""
| if .ewords[$word]
then .add = .ewords[$word]
elif .ewords[$word[0:-1]] and ($word|endswith("."))
then .add = .ewords[$word[0:-1]] + .ewords["DOT"]
elif $word|startswith("CODE")
then .add = "6" + $word[4:]
else .figs = false
| reduce ($word|chars) as $c (.;
if (efigs|contains($c))
then if .figs
then .add += 2 * $c
else .figs = true
| .add += .ewords["FSL"] + 2 * $c
end
else .emap[$c] as $ec
| if ($ec|not)
then "Message contains unrecognized character '\($c)'" | error
else if .figs
then .add += .ewords["FSL"] + $ec
| .figs = false
else .add += $ec
end
end
end )
| if .figs and ($i < $wc - 1)
then .add += .ewords["FSL"]
else .
end
end
| .res += .add
| if ($i < $wc - 1) then .res += .ewords["SPC"] else . end
)
| .res ;
def decode:
{s: .} + checkerboard
| .ewords["FSL"] as $fsl
| .res = ""
| .figs = false
| until (.s == "";
.s[0:1] as $c
| .ix = -1
| if .figs
then if (.s | startswith($fsl) | not)
then .res += $c
else .figs = false
end
| .s |= .[2:]
else .ix = (drow1|index($c))
| if .ix and .ix >= 0
then .res += .dmap[drow1[.ix:.ix+1]]
| .s |= .[1:]
elif $c == "6"
then .res += "CODE" + .s[1:4]
| .s |= .[4:]
elif $c == "7" or $c == "8"
then .s[1:2] as $d
| .res += .dmap[$c + $d]
| .s |= .[2:]
elif $c == "9"
then .s[1:2] as $d
| if $d == "0"
then .res += " "
elif $d == "1"
then .res += "."
elif $d == "8"
then .figs |= not
else .res += .dwords[$c + $d]
end
| .s |= .[2:]
end
end )
| .res ;
### Demonstration
def demo:
"Message:\n\(.)",
(encode
| "\nEncoded:\n\(.)",
"\nDecoded:\n\(decode)" );
"Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March"
| demo
- Output:
Message: Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March Encoded: 0727923909290884848290949190629190979073848257518290982200000098909990549075819070889098119890790827175 Decoded: ADMIN ACK YOUR MSG. CODE291 SEND FURTHER 2000 SUPP TO HQ BY 1 MARCH
Julia
const row1, row2, row3, row4 = "AEINOT", "BCDFGHJKLM", "PQRSUVWXYZ", " ."
const emap = Dict{String,String}()
for (row, k) in [(row1, -1), (row2, 69), (row3, 79), (row4, 89)]
for i in eachindex(row)
emap[string(row[i])] = string(i + k)
end
end
const dmap = Dict{String,String}(v => k for (k, v) in emap)
const ewords = Dict{String,String}(
"ACK" => "92",
"REQ" => "93",
"MSG" => "94",
"RV" => "95",
"GRID" => "96",
"SEND" => "97",
"SUPP" => "99",
)
const dwords = Dict{String,String}(v => k for (k, v) in ewords)
const efigs, spc, dot, fsl, drow1 = "0123456789", "90", "91", "98", "012345"
function encode(s)
s, res = uppercase(s), ""
words = split(s, r"\s")
wc = length(words)
for i = 1:wc
word, add = words[i], ""
if haskey(ewords, word)
add = ewords[word]
elseif haskey(ewords, word[begin:end-1]) && word[end] == "."
add = ewords[word[begin:end-1]] * dot
elseif startswith(word, "CODE")
add = "6" * word[begin+4:end]
else
figs = false
for c in word
if contains(efigs, c)
if figs
add *= c^2
else
figs = true
add *= fsl * c^2
end
else
ec = get(emap, string(c), "")
isempty(ec) && error("Message contains unrecognized character $c.")
if figs
add *= fsl * ec
figs = false
else
add *= ec
end
end
end
if figs && i <= wc - 1
add *= fsl
end
end
res *= add
if i <= wc - 1
res *= spc
end
end
return res
end
function decode(s)
res, sc, figs, i = "", length(s), false, 1
while i <= sc
ch = s[i]
c = string(ch)
if figs
if s[i:i+1] != fsl
res *= c
i += 2
else
figs = false
i += 2
end
elseif !((ix = findfirst(==(ch), drow1)) isa Nothing)
res *= dmap[string(drow1[ix])]
i += 1
elseif c == "6"
res *= "CODE" * s[i+1:i+3]
i += 4
elseif c == "7" || c == "8"
d = string(s[i+1])
res *= dmap[c*d]
i += 2
elseif c == "9"
d = string(s[i+1])
if d == "0"
res *= " "
elseif d == "1"
res *= "."
elseif d == "8"
figs = !figs
else
res *= dwords[c*d]
end
i += 2
end
end
return res
end
const msg = "Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March"
println("Message:\n$msg")
enc = encode(msg)
println("\nEncoded:\n$enc")
dec = decode(enc)
println("\nDecoded:\n$dec")
- Output:
Message: Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March Encoded: 07279239092908848482907983749190629190979073848257518290982200000098909990549075819070889098119890790827175 Decoded: ADMIN ACK YOUR MSG. CODE291 SEND FURTHER 2000 SUPP TO HQ BY 1 MARCH
Phix
Note this includes the two tiny tweaks to encode digits in two characters, as per "Moot point" on the talk page.
with javascript_semantics
constant emap = new_dict(),
dmap = new_dict(),
ewds = new_dict(),
dwds = new_dict(),
spc = "90", dot = "91", fsl = "98"
for d in {{"AEINOT",-1},{"BCDFGHJKLM",69},{"PQRSUVWXYZ",79},{" .",89}} do
integer k = d[2]
for i,ch in d[1] do
string ik = sprintf("%d",i+k)
setd(ch,ik,emap)
setd(ik,ch,dmap)
end for
end for
for d in {{"ACK","92"},{"REQ","93"},{"MSG","94"},{"RV","95"},
{"GRID","96"},{"SEND","97"},{"SUPP","99"}} do
string {k,v} = d
setd(k,v,ewds)
setd(v,k,dwds)
end for
function encode(string s)
string res = ""
sequence words = split(upper(s))
integer wc = length(words)
for i=1 to wc do
string wrd = words[i], a = ""
if getd_index(wrd,ewds) then
a = getd(wrd,ewds)
elsif getd_index(wrd[1..-2]) and wrd[$] == '.' then
a = getd(wrd[1..-2],ewds) & dot
elsif begins("CODE",wrd) then
a = "6" & wrd[5..$]
else
bool figs = false
for c in wrd do
if find(c,"0123456789") then -- (efigs)
if not figs then figs = true; a &= fsl end if
-- a &= repeat(c,3)
a &= repeat(c,2)
elsif not getd_index(c,emap) then
throw("Message contains unrecognized character %c.",{c})
else
if figs then figs = false; a &= fsl end if
a &= getd(c,emap)
end if
end for
if figs and i<=wc-1 then a &= fsl end if
end if
res &= a
if i <= wc-1 then res &= spc end if
end for
return res
end function
function decode(string s)
string res = ""
integer sc = length(s), figs = false, i = 1
while i <= sc do
integer c = s[i]
if figs then
if s[i..i+1] != fsl then
res &= c
-- i += 3
i += 2
else
figs = false
i += 2
end if
elsif find(c,"012345") then -- row 1
res &= getd(c&"",dmap)
i += 1
elsif c == '6' then
res &= "CODE" & s[i+1..i+3]
i += 4
elsif c == '7'
or c == '8' then
res &= getd(s[i..i+1],dmap)
i += 2
elsif c == '9' then
integer d = s[i+1]
if d == '0' then
res &= " "
elsif d == '1' then
res &= "."
elsif d == '8' then
figs = not figs
else
res &= getd(s[i..i+1],dwds)
end if
i += 2
end if
end while
return res
end function
constant msg = "Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March",
enc = encode(msg),
unc = decode(enc)
printf(1,"Message:\n%s\n\nEncoded:\n%s\n\nDecoded:\n%s\n",{msg,enc,unc})
- Output:
Message: Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March Encoded: 07279239092908848482907983749190629190979073848257518290982200000098909990549075819070889098119890790827175 Decoded: ADMIN ACK YOUR MSG. CODE291 SEND FURTHER 2000 SUPP TO HQ BY 1 MARCH
Python
See the discussion for the different checkerboard table handling.
""" rosettacode.org/wiki/Extended_Straddling_Checkerboard """
from functools import reduce
WDICT = {
'CODE': 'κ',
'ACK': 'α',
'REQ': 'ρ',
'MSG': 'μ',
'RV': 'ν',
'GRID': 'γ',
'SEND': 'σ',
'SUPP': 'π',
}
# reversed WDICT for reverse lookup on decode
SDICT = {v: k for (k, v) in WDICT.items()}
# CT37w at https://www.ciphermachinesandcryptology.com/en/table.htm
CT37w = [['', 'A', 'E', 'I', 'N', 'O', 'T', 'κ', '', '', '',],
['7', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M',],
['8', 'P', 'Q', 'R', 'S', 'U', 'V', 'W', 'X', 'Y', 'Z',],
['9', ' ', '.', 'α', 'ρ', 'μ', 'ν', 'γ', 'σ', 'π', '/'],]
# Modified CT37w: web site CT37w, but exchange '/' (FIG) char and 'π'
# to help differentiate the '999' encoding for a '9' from a terminator code
CT37w_mod = [['', 'A', 'E', 'I', 'N', 'O', 'T', 'κ', '', '', '',],
['7', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M',],
['8', 'P', 'Q', 'R', 'S', 'U', 'V', 'W', 'X', 'Y', 'Z',],
['9', ' ', '.', 'α', 'ρ', 'μ', 'ν', 'γ', 'σ', '/', 'π',],]
def xcb_encode(message, table=CT37w, code='κ', wdict=WDICT):
"""
Encode with extended straddling checkerboard. Default checkerboard is
CT37w at https://www.ciphermachinesandcryptology.com/en/table.htm
The numeric mode has the numbers as repeated in triplicate
The CODE mode expects a 3-digit numeric code
"""
encoded = []
numericmode, codemode = False, False
codemodecount = 0
if table[-1][-1] == '/':
nchangemode = '99'
digit_repeats = 3
else:
nchangemode = '98'
digit_repeats = 2
# replace terms found in dictionary with a single char symbol that is in the table
s = reduce(lambda x, p: x.replace(
p[0], p[1]), wdict.items(), message.upper())
for c in s:
if c.isnumeric():
if codemode: # codemode symbols are preceded by the CODE digit '6' then as-is
encoded.append(c)
codemodecount += 1
if codemodecount >= 3:
codemode = False
else:
if not numericmode:
numericmode = True
encoded.append(nchangemode) # FIG
encoded.append(c*digit_repeats)
else:
codemode = False
if numericmode:
# end numericmode with the FIG numeric code for '/' (98)
encoded.append(nchangemode)
numericmode = False
if c == code:
codemode = True
codemodecount = 0
for row in table:
if c in row:
k = row.index(c)
encoded.append(str(row[0]) + str(k-1))
break
return ''.join(encoded)
def xcb_decode(s, table=CT37w, code='κ', sdict=SDICT):
""" Decode extended straddling checkerboard """
prefixes = sorted([row[0] for row in table], reverse=True)
pos, numericmode, codemode = 0, False, False
decoded = []
if table[-1][-1] == '/':
nchangemode = '99'
digit_repeats = 3
else:
nchangemode = '98'
digit_repeats = 2
numbers = {c*digit_repeats: c for c in list('0123456789')}
while pos < len(s):
if numericmode:
if s[pos:pos+digit_repeats] in numbers:
decoded.append(numbers[s[pos:pos+digit_repeats]])
pos += digit_repeats - 1
elif s[pos:pos+2] == nchangemode:
numericmode = False
pos += 1
elif decoded[-1] == '9': # error, so backtrack if last was 9
decoded.pop()
numericmode = False
pos -= digit_repeats - 1
elif codemode:
if (s[pos:pos+3]).isnumeric():
decoded.append(s[pos:pos+3])
pos += 2
codemode = False
elif s[pos:pos+2] == nchangemode:
numericmode = not numericmode
pos += 1
else:
for p in prefixes:
if s[pos:].startswith(p):
n = len(p)
row = next(i for i, r in enumerate(table) if p == r[0])
c = table[row][int(s[pos+n])+1]
decoded.append(c)
if c == code:
codemode = True
pos += n
break
pos += 1
return reduce(lambda x, p: x.replace(p[0], p[1]), sdict.items(), ''.join(decoded))
if __name__ == '__main__':
MESSAGE = 'Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March'
print(MESSAGE)
print('Encoded: ', xcb_encode(MESSAGE))
print('Decoded: ', xcb_decode(xcb_encode(MESSAGE)))
print('Encoded: ', xcb_encode(MESSAGE, CT37w_mod))
print('Decoded: ', xcb_decode(xcb_encode(MESSAGE, CT37w_mod), CT37w_mod))
- Output:
Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March Encoded: 072792390929088484829094919062919097907384825751829099222000000000999098905490758190708890991119990790827175 Decoded: ADMIN ACK YOUR MSG. CODE291 SEND FURTHER 2000 SUPP TO HQ BY 1 MARCH Encoded: 0727923909290884848290949190629190979073848257518290982200000098909990549075819070889098119890790827175 Decoded: ADMIN ACK YOUR MSG. CODE291 SEND FURTHER 2000 SUPP TO HQ BY 1 MARCH
Wren
import "./str" for Str
var row1 = "AEINOT"
var row2 = "BCDFGHJKLM"
var row3 = "PQRSUVWXYZ"
var row4 = " ."
var emap = {}
for (i in 0...row1.count) emap[row1[i]] = i.toString
for (i in 0...row2.count) emap[row2[i]] = (70 + i).toString
for (i in 0...row3.count) emap[row3[i]] = (80 + i).toString
for (i in 0...row4.count) emap[row4[i]] = (90 + i).toString
var ewords = {
"ACK": "92", "REQ": "93", "MSG": "94", "RV": "95",
"GRID": "96", "SEND": "97", "SUPP": "99"
}
var efigs = "0123456789"
var spc = "90"
var dot = "91"
var fsl = "98"
var dmap = {}
var dwords = {}
for (k in emap.keys) dmap[emap[k]] = k
for (k in ewords.keys) dwords[ewords[k]] = k
var drow1 = "012345"
var encode = Fn.new { |s|
s = Str.upper(s)
var res = ""
var words = s.split(" ")
var wc = words.count
for (i in 0...wc) {
var word = words[i]
var add = ""
if (ewords.containsKey(word)) {
add = ewords[word]
} else if (ewords.containsKey(word[0...-1]) && word[-1] == ".") {
add = ewords[word[0...-1]] + dot
} else if (word.startsWith("CODE")) {
add = "6" + word[4..-1]
} else {
var figs = false
for (c in word) {
if (efigs.contains(c)) {
if (figs) {
add = add + c * 2
} else {
figs = true
add = add + fsl + c * 2
}
} else {
var ec = emap[c]
if (!ec) {
Fiber.abort("Message contains unrecognized character '%(c)'.")
}
if (figs) {
add = add + fsl + ec
figs = false
} else {
add = add + ec
}
}
}
if (figs && i < wc - 1) add = add + fsl
}
res = res + add
if (i < wc - 1) res = res + spc
}
return res
}
var decode = Fn.new { |s|
var res = ""
var sc = s.count
var figs = false
var i = 0
while (i < sc) {
var c = s[i]
var ix = -1
if (figs) {
if (s[i..i+1] != fsl) {
res = res + c
} else {
figs = false
}
i = i + 2
} else if ((ix = drow1.indexOf(c)) >= 0) {
res = res + dmap[drow1[ix]]
i = i + 1
} else if (c == "6") {
res = res + "CODE" + s[i+1..i+3]
i = i + 4
} else if (c == "7" || c == "8") {
var d = s[i+1]
res = res + dmap[c + d]
i = i + 2
} else if (c == "9") {
var d = s[i+1]
if (d == "0") {
res = res + " "
} else if (d == "1") {
res = res + "."
} else if (d == "8") {
figs = !figs
} else {
res = res + dwords[c + d]
}
i = i + 2
}
}
return res
}
var msg = "Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March"
System.print("Message:\n%(msg)")
var enc = encode.call(msg)
System.print("\nEncoded:\n%(enc)")
var dec = decode.call(enc)
System.print("\nDecoded:\n%(dec)")
- Output:
Message: Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March Encoded: 0727923909290884848290949190629190979073848257518290982200000098909990549075819070889098119890790827175 Decoded: ADMIN ACK YOUR MSG. CODE291 SEND FURTHER 2000 SUPP TO HQ BY 1 MARCH