Replace multiple occurrences of a character

I try to replace multiple occurrences of a character with a single character.

Input:

hhiii!!! hooowww aaareee yyyooou???

Output:

hi! how are you?

public class CharSingleOccurrence {
public static void main(String... args){
charSingleOccurrence("hhiii!!!  hooowww   aaareee   yyyooou???");
}
public static void charSingleOccurrence(String str){
int i=0;
int j=0;
char arr[]=new char[50];
while (i<str.length()-1) {
if(str.charAt(i)!=str.charAt(i+1)){
arr[j]=str.charAt(i);
i++;
j++;
}else{
i++;
}
}
arr[j]=str.charAt(str.length()-1);
for(char c:arr){
System.out.print(c);
}
}
}


Here I need review for

• char arr[]=new char[50];
• arr[j]=str.charAt(str.length()-1);

I think this is oddly complicated...though, I'm 99% sure this can be done with a single line of RegEx, I don't know how from the top of my head1.

This can be shortened to a much simpler and shorter solution, without the need of arrays at all.

String input = "hhiii!!!  hooowww   aaareee   yyyooou???";
StringBuilder output = new StringBuilder();

// Append the first character of the string.
// We can also let the loop start at 0, but then
// we'd need an additional if inside the loop, which
// I'd like to avoid.
output.append(input.charAt(0));

// Start the loop at 1, because we already have the first character.
// We can not
for (int idx = 1; idx < input.length(); idx++) {
// Check the current against the previous character.
if(input.charAt(idx) != input.charAt(idx-1)) {
// If it is not the same, append it.
output.append(input.charAt(idx));
}
}


Of course you'd need to protect yourself from invalid input (empty or null String), and it will also break words with allowed double-characters: foobar, tool, support etc..

• Function name: It's not directly visible what the function does. It should be called something along the lines of removeDoubleChars or removeMultipleCharacters.
• Function type: The function shouldn't directly output the result to System.out but rather return it.
• Loops: Use appropriate loops, f.e. your while should be a for.
• Variable names: I know it's partly taught, but I get the creeps (or become a Creeper) if I see variables which are named i, j or arr. Give your variables meaningful names! In any modern language the name of the variable is neither limited nor does it matter for performance. Write your code primarily for humans, and only secondary for machines...the coder which has to maintain your code after you will thank you.
• Whitespaces: Use 'em! if(str.charAt(i)!=str.charAt(i+1)){  is harder to read then if(str.charAt(i) != str.charAt(i + 1)) {.
• Code duplication: Avoid duplicate code. In this case it's minor, but the i++ should be moved outside the if, so that it's not necessary to have an else part.
• I'm sorry but the logic I'd to implement is in the same way I wrote my code, but the thing I need is that what can I do with char arr[]=new char[50]; so that I don't have to predefine the size of array(char[50]); Commented Oct 28, 2011 at 12:55
• @MohammadFaisal: Use a List. Commented Oct 28, 2011 at 12:58
• The output you get will not be a meaningful word if a word "happpy" is given, as it allows two p's in it. But when executed, your code removes all the duplicate characters, so the output will be "hapy," which is not a dictionary word. Commented Mar 21, 2014 at 5:52

Maybe I am wrong but I prefers to use the regex for this kind of text manipulation. Here is my code,

System.out.println("hhiii!!!  hooowww   aaareee   yyyooou???"
.replaceAll("(.)\\1+","\$1"));

• :No, you are not wrong but I don't have to do like that.... I'd to make my own logic for regex or something like that. Commented Oct 27, 2011 at 7:37
• Agreed always use tools that are there. But it regex is always worth an extra line of comments. Commented Oct 27, 2011 at 7:49
• regex is definitely the most graceful solution Commented Oct 27, 2011 at 10:36

A StringBuilder is good for building strings. I suggest that you keep track of the last character that you put in the builder to avoid the repeated characters.

This is C# code, but I think that it should translate to Java easily enough:

public static string CharSingleOccurance(string value) {
StringBuilder result = new StringBuilder();
char? last = null;
foreach (char c in value) {
if (!last.HasValue || c != last.Value) {
result.Append(c);
last = c;
}
}
return result.ToString();
}


Edit:

Here is Bobbys suggestion for a Java translation:

public static String charSingleOccurance(String value) {
StringBuilder result = new StringBuilder();
char last = '\u0000';

for (char c : value.toCharArray()) {
if (last == '\u0000' || c != last) {
result.append(c);
last = c;
}
}

return result.toString();
}

• Variable last should be boolean. Commented Oct 27, 2011 at 15:35
• @palacsint: It is. The nullable char contains both a char value and a boolean that determines if it's null or not. Commented Oct 27, 2011 at 16:10
• @palacsint: Why? It's the last appended character, it can't be boolean. Commented Oct 27, 2011 at 19:49
• Sorry guys, you're right. It have to be char, I've overlooked the spec/question. Commented Oct 27, 2011 at 20:24