Packed Ascii

May 6, 2014

Packed ascii is a method for compressing a useful subset of ascii characters in 6 bits, used in HART-enabled devices. The characters that may be transmitted are the space character, the 26 upper-case letters, the 10 digits, and the following punctuation characters: ! " # $ % & ' ( ) * + , - . / : ; ? @ [ \ ] ^ _. Omitted are the 26 lower-case letters, the rubout character, and the following punctuation characters: ` { | } ~.

Compression is achieved by keeping only the six low-order bits of each ascii character. Compressed characters are expanded to their original character by adding a high-order bit that is the complement of the compressed high-order bit. For instance, the string “PRAXIS” is compressed as the six 6-bit binary numbers 010000 010010 000001 011000 001001 010011.

A string of characters is compressed to 6-bit characters, then transmitted as 8-bit bytes by packing the bits from high-order to low-order, so that four characters are transmitted in three bytes, achieving a 25% compression. If the message length is not an even multiple of four, space characters are added to the end of the string as padding. Thus, the six 6-bit binary numbers representing “PRAXIS” would be padded with two space characters and transmitted as the six 8-bit binary numbers 01000001 00100000 01011000 00100101 00111000 00100000, which corresponds to the string “A X%8 “.

Your task is to write functions that compress and expand strings in packed ascii format. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.


Pages: 1 2

One Response to “Packed Ascii”

  1. chmllr said

    I feel a little bit like cheater using Java’s Integer methods for parsing and generating bit strings, but in the end, this is why my choice is Clojure :)

    (defn compress [input]
      (let [pad (repeat (mod (count input) 4) \ )
            padded-input (concat input pad)
            truncated (map #(bit-and 63 (int %)) padded-input)
            bit-strings (map #(Integer/toString % 2) truncated)
            prefixed (map #(str (apply str (repeat (- 6 (count %)) "0")) %) bit-strings)
            compressed (map #(apply str %) (partition 8 (apply str prefixed)))
            bytes (map #(char (Integer/parseInt % 2)) compressed)]
        (apply str bytes)))
    (defn expand [input]
      (let [bit-strings (map #(Integer/toString (int %) 2) input)
            prefixed (map #(str (apply str (repeat (- 8 (count %)) "0")) %) bit-strings)
            merged (apply str prefixed)
            ints (map #(Integer/parseInt (apply str %) 2) (partition 6 merged))
            expanded (map #(if (= 32 %) % (bit-or 64 %)) ints)]
          (apply str (map char expanded)))))

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: