Last active
August 29, 2015 14:19
-
-
Save milankarunarathne/2c7f1f4456be4f858374 to your computer and use it in GitHub Desktop.
Decode messages under a scheme
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
* @author : Milan Karunarathne | |
* @email : [email protected] | |
* @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