In: Computer Science
(Java)Run length encoding is a simple form of data compression. It replaces long sequences of a repeated value with one occurrence of the value and a count of how many times to repeat it. This works reasonably well when there are lots of long repeats such as in black and white images. To avoid having to represent non-repeated runs with a count of 1 and the value, a special value is often used to indicate a run and everything else is just treated as a simple value. For this exercise you will decompress one line of input at at time assuming the line was compressed according to the following:
The newline characters are passed through uncompressed even when there are repeated blank lines. When a run of n>=3 repeated characters, c, is detected where c is NOT a digit, the run will be replaced with #nc. When a run of n>=3 repeated characters, c, is detected where c IS a digit, the run will be replaced with #n#c. The extra # is needed to avoid confusing the repeated digit c with the last digit of the run count. All other characters (i.e. runs of just 1 or 2 characters) are passed through unmodified. Assume the uncompressed input does not contain the symbol '#'. This assumption can be eliminated. You might think about how you would do it.
Some examples:
abc decompresses to abc
#3ab#4c decompresses to aaabcccc
abc12#14#3 decompresses to abc1233333333333333
Your decoder can assume the input was properly compressed, i.e. no need for error checking. Your program must include a public static method decompress() that takes one parameter, a String, that is the line to be decompressed. The method returns the decompressed String. Write Decoder.java to answer this question.
The length encoding is a simple form of data compression. It replaces long sequences of a repeated value with one occurrence of the value and a count of how many times to repeat it. This works reasonably well when there are lots of long repeats such as in black and white images. To avoid having to represent non-repeated runs with a count of 1 and the value, a special value is often used to indicate a run and everything else is just treated as a simple value. For this exercise you will decompress one line of input at at time assuming the line was compressed according to the blow giving code and the data.
package com;
import java.util.HashMap;
public class Encoder {
public static void main(String[] args) {
String s = "aabc1233333333333333";
s = "abc";
/*s = ""
+ " "
+ " "
+ "";*/
//s= "aaabcccc";
//s = "aaa";
s = "aa";
System.out.print(compress(s));
//System.out.print(countCharacters(s));
}
/**
* This method will accept the String and count the each character
and put it in the map as key value pair.
* Key : Character
* Value : Count
*
* Count is start from 0 like an array. If count = 0 then it means
it has 1 value.
* example -
* input : "aabc1233333333333333"
* Output : {a=1, 1=0, b=0, 2=0, c=0, 3=13}
*
* @param input - It takes string as input.
* @return HashMap contain count of each character.
*/
public static HashMap<Character, Integer>
countCharacters(String input ) {
HashMap<Character, Integer> map = new
HashMap<Character, Integer>(); // Creating a map for counting
character
int len = input.length();
char[] characters = input.toCharArray();
/** Here we creating a character array of given String and
iterating each character.
If map contains that character then we increase it's value.
If map not contains that character then we put 0
*/
for (int i = 0; i < len; i++) {
if (map.containsKey(characters[i])) {
Integer count = map.get(characters[i]);
map.put(characters[i], ++count);
} else {
map.put(characters[i], 0);
}
}
return map;
}
/**
* This method take input as String. Process that String as given
condition and return as encoded String.
* For detail understanding see each lines comments.
* Example
* Input : abc
* Output : abc
*
* Input : aaabcccc
* Output : #3ab#4c
*
* @param input - It takes string as input.
* @return encoded String
*/
public static String compress(String input) {
int len = input.length();
/**
* If the given String length is less than 3 then we retrun same
String.
* Example :
* Input : ab
* Output : ab
*/
if(len < 3 ){
return input;
}
/*Call the method that will return map who contains count of
each character*/
HashMap<Character, Integer> map = countCharacters(input);
StringBuffer finalString = new StringBuffer();
char[] characters = input.toCharArray();
/**
* For Each loop we check if the given character is present in the
map or not.
* If char is Present in a Map -
* we take count from Map.
* If count is gretter than or equal to 2 .
* then we check it is digit or character for differentiating for
'#'
* based on we append that character to finalString.
* If Count is less than 2
* then we direct append that character to finalString.
*
*
* And Finally we remove this character from map. For remove
repetition. The If case used for not to come exception
ArrayIndexOutofBound.
* Means i is always == Or less than then then only we can remove
from map.
* If char is not Present in a Map -
* This case will never occur
*
*
*
*/
for (int i = 0; i < len; i++) {
if (map.containsKey(characters[i])) {
int count = map.get(characters[i]);
if (count != 0 && count >= 2) {
if (Character.isDigit(characters[i])) {
finalString.append("#" + ++count + "#" + characters[i]);
} else {
finalString.append("#" + ++count + characters[i]);
}
} else {
finalString.append(characters[i]);
}
if ((i + 1) <= len && (i + 2) <= len &&
characters[i] == characters[i + 1]
&& characters[i] == characters[i + 2]) { /*The If case used
for not to come exception ArrayIndexOutofBound. Means i is always
== Or less than*/
map.remove(characters[i]);
}
}
}
return finalString.toString();
}
}