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);
up vote 11 down vote accepted

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..

Some further comments on your code:

  • 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.

1: But John does.

  • 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]); – Mohammad Faisal Oct 28 '11 at 12:55
  • 1
    @MohammadFaisal: Use a List. – Bobby Oct 28 '11 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. – user3445051 Mar 21 '14 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. – Mohammad Faisal Oct 27 '11 at 7:37
  • Agreed always use tools that are there. But it regex is always worth an extra line of comments. – Martin York Oct 27 '11 at 7:49
  • 4
    regex is definitely the most graceful solution – luketorjussen Oct 27 '11 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. – palacsint Oct 27 '11 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. – Guffa Oct 27 '11 at 16:10
  • @palacsint: Why? It's the last appended character, it can't be boolean. – Bobby Oct 27 '11 at 19:49
  • Sorry guys, you're right. It have to be char, I've overlooked the spec/question. – palacsint Oct 27 '11 at 20:24

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.