Skip to content

Instantly share code, notes, and snippets.

@milankarunarathne
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milankarunarathne/2c7f1f4456be4f858374 to your computer and use it in GitHub Desktop.
Save milankarunarathne/2c7f1f4456be4f858374 to your computer and use it in GitHub Desktop.
Decode messages under a scheme
/******************************************************************************
* @author : Milan Karunarathne
* @email : mhkarunarathne@gmail.com
* @summary : Decode messages under a encoding scheme such as
* a sequence of "key" strings of 0's and 1's as follows:
* 0,00,01,10,000,001,010,011,100,101,110,0000,0001,...,
* 1011,1110,00000, ...
* The keys are mapped to the characters in a given header in order.
*****************************************************************************/
'use strict';
var fs = require('fs');
/***********************************************************
* @class Decoder
* @summary Decode message by reading segments and
* encoding scheme.
**********************************************************/
function Decoder() {
this.headerMap = {};
this.encodeScheme = new EncodeScheme();
}
/**
* @param data The data set to be decode
* @return Decoded message as a string
*/
Decoder.prototype.decodeMSG = function( /*string*/ data) {
var header = this.separateHeaderAndMSG(data);
var msg = header.msg;
header = header.header;
this.headerMap = this.encodeScheme.mappingHeaderCharacters(header);
var segments = this.readSegments(msg);
var decodedMSG = '';
for (var i in segments) {
decodedMSG += this.decodeSegment(segments[i]);
}
return decodedMSG;
};
/**
* @param data The data set to be separate into header and message
* @return Object which contains header and message(msg)
*/
Decoder.prototype.separateHeaderAndMSG = function(data) {
//TODO: Need to handle errors (when not represent any 0's or 1's).
// Find last occurrence of any character (ignoring 0's and 1's)
var position = data.search(/[^01](?!.*[^01])/g);
// Check whether current message may terminate with 000's
var keyLength = 0,
isValidMSG = false,
msg = '';
// Start from occurrence of 0's and 1's and repeat until find a message
// which is ended with 0 (000 in binary)
do {
position++;
msg = data.substr(position);
var endChecker = '1111111111';
do {
keyLength = parseInt(msg.substr(0, 3), 2);
msg = msg.substr(3);
// Iterate forward until the end of segment
var key = '';
do {
if (msg.length >= keyLength) {
// Read a key of given length for the current segment
key = msg.substr(0, keyLength);
msg = msg.substr(keyLength);
isValidMSG = true;
} else {
// Break reading segment if can't read a proper key
isValidMSG = false;
break;
}
} while (key !== endChecker.substr(0, keyLength));
// Terminate if current key contains only 1's
} while (keyLength && isValidMSG);
// Terminate if key length is 0 (000 in binary)
// Continuous read segments if a valid message up to now
} while (msg.length); // Until find a valid message (terminate with 000's)
return {
header: data.substr(0, position),
msg: data.substr(position)
};
};
/**
* @param msg The message to be decoded (without header)
* @return A array of segments. Each segment is represent as an array of keys
* e.g. [ ['01', '10', '00], ['000', '010']]
*/
Decoder.prototype.readSegments = function(msg) {
var segments = [];
var segmentCnt = 0;
// Get Key string length
var keyLength = 0;
var endChecker = '1111111111';
do {
keyLength = parseInt(msg.substr(0, 3), 2);
msg = msg.substr(3);
// Iterate forward until the end of segment
var key = '',
segment = [];
do {
if (key !== '') {
segment.push(key);
}
// Read a key of given length for the current segment
key = msg.substr(0, keyLength);
msg = msg.substr(keyLength);
} while (key !== endChecker.substr(0, keyLength));
// Added to the segments if current segment has any key
if (segment.length) {
segments.push(segment);
}
segmentCnt++;
} while (keyLength); // Terminate if key length is 0 (000 in binary)
return segments;
};
/**
* @param segment An array of keys to be decoded
* @return Decoded segment with using Encoded scheme as a string
*/
Decoder.prototype.decodeSegment = function(segment) {
var decodedSegment = '';
for (var i in segment) {
decodedSegment += this.headerMap[segment[i]];
}
return decodedSegment;
};
/***********************************************************
* @class Encoding Scheme
**********************************************************/
function EncodeScheme() {}
/**
* @param header The header of data set to be decoded
* @return Object which keys are encoded scheme's keys s.t. 0,00,01,10
* and values are header characters
*/
EncodeScheme.prototype.mappingHeaderCharacters = function(header) {
var map = {};
var sequence = this.generateKeySequence();
for (var i = 0; i < header.length; i++) {
map[sequence[i]] = header.charAt(i);
}
return map;
};
/**
* @return An array of encoding scheme keys s.t. 0,00,01,10 in order
*/
EncodeScheme.prototype.generateKeySequence = function() {
var sequence = [];
for (var l = 1; l < 8; l++) {
for (var i = 0; i < Math.pow(2, l) - 1; i++) {
sequence.push(this.convertDecToBinary(i, l));
}
}
return sequence;
};
/**
* @param dec The decimal number
* @param length The length of the output binary representation
*/
EncodeScheme.prototype.convertDecToBinary = function(dec, length) {
var num = dec.toString(2);
if (num.length !== length) {
if (num.length < length) {
// Append 0's at the beginning of number until it's length equals to
// given length. e.g. 3 -> 11 -> 0011
num = '0000000'.substr(0, (length - num.length)) + num;
} else {
throw new Error("convertDecToBase(): num(" + num + ").length > length(" +
length + ") too long.");
}
}
return num;
};
/***********************************************************
* Read data set from file and write output
**********************************************************/
// Create a decode object
var decoder = new Decoder();
// Read input file
var inputFileName = process.argv[2] || 'input.txt';
var input = fs.readFileSync(inputFileName).toString().split('\n');
// Create a output file, and remove any existing content
var outputFileName = process.argv[3] || 'output.txt';
fs.writeFileSync(outputFileName, '');
// Iterate through each line of data set
for (var line in input) {
if (input[line].length) {
// Write to the output file
fs.appendFileSync(outputFileName, decoder.decodeMSG(input[line]) + '\n');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment