Java - Compressed String - java

Given a string, I want to compress the string based on each character's number of consecutive occurrences next to it. For example, let's say we have a string like "abaasass". 'a' occurs one time, 'b' occurs one time, 'a' occurs two times consecutively, 's' occurs one time, 'a' occurs one time, and 's' occurs two times consecutively. The method should then return a string like "aba2sas2".
This is what I have so far:
public static String compressedString(String message) {
StringBuilder compressedString = new StringBuilder();
int total = 0;
for (int i = 0; i < message.length() - 1; i++){
if (message.charAt(i) == message.charAt(i+1)){
total += 2;
compressedString.append(message.charAt(i)).append(total);
}
else {
compressedString.append(message.charAt(i));
}
total = 0;
}
return compressedString.toString();
}
It instead returns: "aba2asas2" which is somewhat close, anyone sees the issue?

public static String compressedString(String message) {
StringBuilder compressedString = new StringBuilder();
int total = 1;
for (int i = 0; i < message.length() - 1; i++){
if (message.charAt(i) == message.charAt(i+1)){
total++;
}
else if(total==1){
compressedString.append(message.charAt(i));
}
else
{
compressedString.append(message.charAt(i)).append(total);
total = 1;
}
}
if(message.charAt(message.length()-2) != message.charAt(message.length()-1)
compressedString.append(message.charAt(message.length()-1));
else
compressedString.append(message.charAt(message.length()-1)).append(total);
return compressedString.toString();
}

public static String compressedString(String message)
{
String result = "" ;
for ( int i = 0, t = message.length() - 1 ; i < t ; )
{
String letter = String.valueOf( message.charAt(i) ) ;
int currentChain = consec( i, message ) ;
result += ( currentChain > 1 ? ( letter + currentChain ) : letter ) ;
i += currentChain ;
}
return result ;
}
private static int consec( int startIndex, String text )
{
int chain = 1 ;
for( int i = startIndex ; i < text.length() - 1 ; ++i )
{
if( text.charAt(i) == text.charAt(i+1) )
chain++ ;
else
break ;
}
return chain ;
}

This is your solution for your question
static void compressedString(String str) {
int n = str.length();
for (int i = 0; i < n; i++) {
// Count occurrences of current character
int count = 1;
while (i < n - 1 && str.charAt(i) == str.charAt(i + 1)) {
count++;
i++;
}
if (count == 1) {
System.out.print(str.charAt(i));
} else {
System.out.print(str.charAt(i));
System.out.print(count);
}
}
}
public static void main(String[] args) {
String str = "abaasass";
compressedString(str);
}

Related

How do I avoid exception in the second iteration?

I'm trying to display the number of times a letter appears within a string and outputting it in a new string (compressedString).
For example: aabcccccaaa should display a2b1c5a3.
So far, I got a2 to display only because I've included the break statement. If I took that out, then I would get StringIndexOutOfBoundsException.
My question is: How would I continue going through the whole string to obtain the rest of the aforementioned output without getting StringIndexOutOfBoundsException?
I ran it through debugger but it still isn't clear to me.
public class Problem {
public static void main(String []args) {
String str = "aabcccccaaa";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
int countConsecutive = 0;
String compressedString = "";
for(int i = 0; i < str.length(); i++) {
countConsecutive++;
if(str.charAt(i) != str.charAt(i + 1)) {
compressedString += "" + str.charAt(i) + countConsecutive;
break;
}
}
return compressedString;
}
}
modify your for loop to terminate when i < str.length() - 1--this is because you are comparing the character at i to the character at i + 1, which makes your loop go out of bounds.
Try this
public class Problem {
public static void main(String []args) {
String str = "aaabc";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
int countConsecutive = 0;
String compressedString = "";
for(int i = 0; i < str.length(); i++) {
countConsecutive++;
//avoid index out of bounds error
if(str.length() == (i + 1)){
compressedString += ""+ str.charAt(i) + countConsecutive;
countConsecutive = 0;
break;
}
else if(str.charAt(i) != str.charAt(i + 1)){
compressedString += ""+ str.charAt(i) + countConsecutive;
countConsecutive = 0;
}
}
return compressedString;
}
}
The other answers have good solutions, but I thought I would just add what I came up with:
public class Problem {
public static void main(String []args) {
String str = "aabcccccaaa";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
if (str.length() == 1) return str + "1"; // Handles single character strings
int countConsecutive = 0;
String compressedString = "";
for (int i = 0; i < str.length(); i++) {
if (i > 0) {
countConsecutive++;
if (str.charAt(i) != str.charAt(i-1)) {
compressedString += "" + str.charAt(i-1) + countConsecutive;
countConsecutive = 0;
}
if (i == str.length()-1) {
countConsecutive++; // Needs to be incremented for the last character
compressedString += "" + str.charAt(i) + countConsecutive;
}
}
}
return compressedString;
}
}
Your condition should be like this:
if(i+1 < str.length() && str.charAt(i) != str.charAt(i + 1))
because when you are is at last index of your string then also you are comparing i'th index with i+1 th index.
But after correcting this, still, this code will not give you the expected output.
This is how I would change the code.
public static String compressBad(String str) {
String compressedString = "";
if (str != null && str.length() > 0) {
int countConsecutive = 1;
char prevChar = str.charAt(0);
for (int i = 1; i < str.length(); i++) {
if (str.charAt(i) != prevChar) {
// End of a run. Update compressedString and reset counters
compressedString += String.valueOf(prevChar) + countConsecutive;
prevChar = str.charAt(i);
countConsecutive = 1;
continue;
}
countConsecutive++;
}
compressedString += String.valueOf(prevChar) + countConsecutive;
}
return compressedString;
}
Mukit09 has already mentioned the reason for your StringIndexOutOfBoundsException.
I offer you a more efficient implementation, using String Builder for concatenating strings:
private static String comppressedString(String str) {
if(str == null || str.equals("")) {
return str;
}
if(str.length() == 1) {
return str + "1";
}
StringBuilder sb = new StringBuilder();
sb.append(str.charAt(0)); // Add first letter
int j = 1; // Counter for current sequence length.
for (int i = 0; i < str.length() - 1; i++) {
if(str.charAt(i) != str.charAt(i + 1)) { // end of characters sequence.
sb.append(j); // Add length of previous sequence.
if(j > 1) {
j = 1; // Minimum sequence length is 1
}
sb.append(str.charAt(i+1)); // Add character of next sequence.
} else {
j++; // increase counter, in order to get the length of the current sequence.
}
}
sb.append(j); // Add length of last sequence.
return sb.toString();
}
public static void main(String[] args) {
System.out.println(comppressedString("")); // empty string
System.out.println(comppressedString("a")); // a1
System.out.println(comppressedString("ab")); // a1b1
System.out.println(comppressedString("abba")); // a1b2a1
System.out.println(comppressedString("aabcccccaaa")); // a2b1c5a3
}

Reading data within parenthesis

I have a string something like
String test = "Happy{{Sad}Blue{{Red}Green}}Purple";
How could I extract the text between the parenthesis, like the following
{Sad}Blue{{Red}Green}
Sad
{Red}Green
Red
I shouldn't, but check this out:
Matcher m = Pattern.compile(test.replace("{", "\\{(").replace("}", ")\\}")).matcher(test);
m.find();
for (int i = 1; i <= m.groupCount(); i++) {
System.out.println(m.group(i));
}
Ideone Demo
It's easy to use the recursive call or the stack data struct to solve the problem. And you can understand what's behind. Here is an example:
public static void main(String[] args) {
String test = "Happy{{Sad}Blue{{Red}Green}}Purple";
findStr(test);
}
public static void findStr(String str){
if(str==null || str.equals("")){
return ;
}
int begin =0;
int end = 0;
String theStr = "";
for(int i =0;i<str.length();i++){
if(str.charAt(i) == '{'){
begin ++ ;
if(begin > 1){
theStr += str.charAt(i);
}
} else if (str.charAt(i) == '}'){
end ++ ;
if(begin == end ){
System.out.println(theStr);
findStr(theStr);
begin = 0;
end = 0;
theStr = "";
}else{
theStr += str.charAt(i);
}
}else if(begin > 0 ){
theStr += str.charAt(i);
}
}
}

Representing a string with more than 4 chars as 4 chars

public class CreditCardNumber {
private String issuerId;
private String accountNum;
private int checkDigit = 9;
private StringBuilder builder;
public CreditCardNumber(String id, String accNum) {
this();
if (id != null && accNum != null && id.length() == 6 && accNum.length() == 9 && isDigit(id) == true
&& isDigit(accNum) == true) {
accountNum = accNum;
issuerId = id;
}
setCheckDigit();
}
public CreditCardNumber() {
issuerId = "000000";
accountNum = "999999999";
}
public String getId() {
return issuerId;
}
public String getAccNum() {
return accountNum;
}
public int getCheckDigit() {
return checkDigit;
}
// A
private void setCheckDigit() {
int sum = checkSum();
int temp = sum + checkDigit;
if(temp%10 != 0) {
int num = temp%10;
checkDigit = checkDigit - num;
}
}
// Method to check if each character in string is a digit
public boolean isDigit(String s) {
boolean condition = true;
for (int i = 0; i < s.length(); i++) {
if (Character.isDigit(s.charAt(i))) {
condition = true;
}
}
return true;
}
// B
public void changeId(String id) {
int max = 9;
int min = 0;
if (id != null && id.length() == 6 && isDigit(id) == true) {
issuerId = id;
}
builder = new StringBuilder();
for (int i = 0; i <= 9; i++) {
int randomNum = (int) (Math.random() * (max - min + 1)) + min;
builder.append(randomNum);
accountNum = builder.toString();
}
setCheckDigit();
}
// C
private int checkSum() {
int sum = 0;
builder = new StringBuilder();
builder.append(issuerId);
builder.append(accountNum);
for (int i = 0; i < builder.length(); i++) {
// In each of the chars with an EVEN index
if (i % 2 == 0) {
int x = Integer.parseInt(Character.toString(builder.charAt(i))); //// get the int value from the char
int y = x * 2; // multiply it by 2
if (y >= 10) {
int z = y % 10;
z += 1; //// if doubling it has 2 digits, add those digits
builder.setCharAt(i, Character.forDigit(z, 10)); // put above result back into the StringBuilder at
// the same index
}
}
}
// Add the values of each digit in the StringBuilder
for (int i = 0; i < builder.length(); i++) {
sum += Integer.parseInt(Character.toString(builder.charAt(i)));
}
return sum;
}
//D
}
/* public String toString() {
a public method called toString (NO PARAMETERS) that returns (in a
return
statement) the issuerID, accountNum and checkDigit , BUT WITH A ' '
(space)
BETWEEN EVERY 4 CHARACTERS! (don't change any of the instance variables
here!)
}
}
*/
So my main issue here is, the directions say that I have to return these variables (all more than 4 digits) but with a delimiter ' ' between every 4 characters. I need some guidance into figuring out how to implement the "every 4 digits" part. Maybe using a StringBuilder? Please help.
To return a String with ' ' delimiters in between every four characters, use these methods:
// Takes a String as input and outputs a formatted String:
public String toFormattedString(String inputString){
StringBuilder returnStringBuilder = new StringBuilder();
for(int i = 0; i < inputString.length(); i++) {
returnStringBuilder.append(inputString.charAt(i));
if(i%4==3) {
returnStringBuilder.append(' ');
}
}
return new String(returnStringBuilder);
}
// Takes a int as input and outputs a formatted String:
public String toFormattedString(int inputInt){
return toFormattedString(Integer.toString(inputInt));
}
You can use these methods in your public String toString() method. I'm just not sure how you want the three Strings to be returned in one String return value. Do you want them appended to each other or returned in a different way?

Change sysout to String

please for help
I need retrurn in 'String dst;' the same result as console
e.g. input txt = "aabbc"; which gives return dst = "a2b2c1"
public String compres(String txt) {
String dst = "";
char character;
int count;
for (int i = 0; i < txt.length(); i++) {
character = txt.charAt(i);
count = 1;
while (i < txt.length() - 1 && txt.charAt(i + 1) == character) {
count++;
i++;
}
System.out.print(character);
System.out.print(count);
}
return dst;
}
Use StringBuilder.
public String compres(String txt) {
StringBuilder dst = new StringBuilder();
char character;
int count;
for (int i = 0; i < txt.length(); i++) {
character = txt.charAt(i);
count = 1;
while (i < txt.length() - 1 && txt.charAt(i + 1) == character) {
count++;
i++;
}
System.out.print(character);
System.out.print(count);
dst.append(character).append(count);
}
return dst.toString();
}
today my mate gave me easiest sollution i need add only in my loop:
dst += character + "" + count;
instead of double sysout

Split string which contains escaped delimiters

delimiter is |
escaping character is \
and string is for example "A|B\|C\\|D\\\|E|\\\\F"
I want to get array:
{"A", "B|C\", "D\|E", "\\F"}
So delimiter can be escaped but escaping character can be also escaped. Does somebody know how to parse this in Java ?
Thanks.
Edit:
I created this terribly looking solution. At least It works perfectly and It is possible to define escaping character, delimiter and if empty string should be removed easily.
SOLUTION (Eggyal posted better one, look down):
private List<String> parseString(String string, String delimiter, boolean removeEmpty) {
String escapingChar = "\\";
String escapingCharInRegexp = "\\\\";
boolean begined = false;
List<String> parsed = new ArrayList<String>();
List<Integer> begins = new ArrayList<Integer>();
List<Integer> ends = new ArrayList<Integer>();
List<Integer> delimitersPositions = new ArrayList<Integer>();
List<String> explodedParts = new ArrayList<String>();
int i;
for(i = 0; i < string.length(); i++) {
if( ( string.substring(i, i+1).equals(escapingChar) || string.substring(i, i+1).equals(delimiter) ) && !begined ) {
begins.add(i);
begined = true;
if( i + 1 == string.length() ) {
begined = false;
ends.add(i+1);
}
} else if( ( !string.substring(i, i+1).equals(escapingChar) && !string.substring(i, i+1).equals(delimiter) && begined ) ) {
begined = false;
ends.add(i);
} else if( begined && string.substring(begins.get(begins.size()-1), i).indexOf(delimiter) != -1 ) {
begined = false;
ends.add(i);
begined = true;
begins.add(i);
}
if( ( i + 1 == string.length() && begined ) ) {
begined = false;
ends.add(i+1);
}
}
List<Integer> toRemove = new ArrayList<Integer>();
for( i = 0; i < begins.size(); i++ ) {
if( string.substring(begins.get(i), ends.get(i)).indexOf(delimiter) == -1 ) {
toRemove.add(i);
}
}
for( i = 0; i < toRemove.size(); i++ ) {
begins.remove(toRemove.get(i)-i);
ends.remove(toRemove.get(i)-i);
}
for( i = 0; i < begins.size(); i++ ) {
if( ( ends.get(i) - begins.get(i) ) % 2 != 0 ) {
delimitersPositions.add(ends.get(i)-1);
}
}
for( i = 0; i <= delimitersPositions.size(); i++ ) {
int start = (i == 0) ? 0 : delimitersPositions.get(i-1)+1;
int end = ( i != delimitersPositions.size()) ? delimitersPositions.get(i) : string.length();
if( removeEmpty ) {
if( !string.substring(start, end).equals("") ) {
explodedParts.add(string.substring(start, end));
}
} else {
explodedParts.add(string.substring(start, end));
}
}
for (i = 0; i < explodedParts.size(); i++)
parsed.add(explodedParts.get(i).replaceAll(escapingCharInRegexp+"(.)", "$1"));
return parsed;
}
static final char ESCAPING_CHAR = '\\';
private List<String> parseString(final String str,
final char delimiter,
final boolean removeEmpty)
throws IOException
{
final Reader input = new StringReader(str);
final StringBuilder part = new StringBuilder();
final List<String> result = new ArrayList<String>();
int c;
do {
c = input.read(); // get the next character
if (c != delimiter) { // so long as it isn't a delimiter...
if (c == ESCAPING_CHAR) // if it's an escape
c = input.read(); // use the following character instead
if (c >= 0) { // only if NOT at end of string...
part.append((char) c); // append to current part
continue; // move on to next character
}
}
/* we're at either a real delimiter, or end of string => part complete */
if (part.length() > 0 || !removeEmpty) { // keep this part?
result.add(part.toString()); // add current part to result
part.setLength(0); // reset for next part
}
} while (c >= 0); // repeat until end of string found
return result;
}
Because you are both splitting and unescaping, you need a separate step for each process:
String[] terms = input.split("(?<=[^\\\\]|[^\\\\]\\\\\\\\)\\|");
for (int i = 0; i < terms.length; i++)
terms[i] = terms[i].replaceAll("\\\\(.)", "$1");
Here's some test code:
public static void main(String[] args) {
String input = "A|B\\|C\\\\|D\\\\\\|E|\\\\\\\\F";
String[] terms = input.split("(?<=[^\\\\]|[^\\\\]\\\\\\\\)\\|");
for (int i = 0; i < terms.length; i++)
terms[i] = terms[i].replaceAll("\\\\(.)", "$1");
System.out.println(input);
System.out.println(Arrays.toString(terms));
}
Output:
A|B\|C\\|D\\\|E|\\\\F
[A, B|C\, D\|E, \\F]
There is no escape sequence in java like you've mentioned "\|".
It'll cause compile time error.

Categories

Resources