user1950349
user1950349

Reputation: 5146

Capitalize various letters in a string

I am working on an interview question:

Capitalize 2nd, 4th, 8th, 16th letters in a string

input - "letters in a string"

output - "lEtTers in a stRing"

Here is my solution:

public static void main(String[] args) {
    String input = "letters in a string";

    String output = input.substring(0, 1) + input.substring(1, 2).toUpperCase() + input.substring(2, 3)
            + input.substring(3, 4).toUpperCase() + input.substring(4, 7) + input.substring(7, 8).toUpperCase()
            + input.substring(8, 15) + input.substring(15, 16).toUpperCase() + input.substring(15);
    System.out.println(output);

}

Is there any way we can generalize this without hard coding the offset numbers here? In general, what I am looking for is - given the letter number which we want to capitalize, our program should work on that without changing the core logic and should be efficient as well in terms of complexity?

Upvotes: 0

Views: 2664

Answers (6)

Ash
Ash

Reputation: 1471

My safer implementation:

public static String toCapitalizedCase(String givenString) {
    if(TextUtils.isEmpty(givenString)){
        return givenString;
    }
    String[] arr = givenString.toLowerCase().split(" ");
    StringBuffer sb = new StringBuffer();

    for (int i = 0; i < arr.length; i++) {
        sb.append(Character.toUpperCase(arr[i].charAt(0)))
                .append(arr[i].substring(1)).append(" ");
    }
    return sb.toString().trim();
}

Upvotes: 0

D. Ben Knoble
D. Ben Knoble

Reputation: 4703

Here is I think the best way:

//here index is the nth letter to capitalize, i.e. 2 changes the character
//at index 1, hence the subtraction
public String capitalize(String s, int index)
{
    StringBuilder sb = new StringBuilder(s);
    sb.setCharAt(index - 1, Character.toUpperCase(sb.charAt(index - 1)));
    return (sb.toString());
}

//indices in the array should the follow the same convention as above
public String capitalize(String s, int[] indices)
{
    for (int i = 0; i < indices.length; i++)
    {
        s = Capitalize(s, indices[i]);
    }
    return s;
}

From here calling the method on retrieved input is simple.

EDIT: After returning to look at this randomly, the creation of a StringBuilder in a loop could be costly, since it's only useful inside one method body. A better way would be to extend the pattern to pass around a StringBuilder reference to the string within the methods (in some private manner) to avoid creating a new one all the time.

Upvotes: 0

Shahzad
Shahzad

Reputation: 2073

As others stated, the best way to do this is by writing a method which you can use more than once. Try this:

public static String capitalize(String string, int[] caps) {
    if (caps[caps.length - 1] > string.length()) {
        return "String not long enough.";
    }
    StringBuilder sb = new StringBuilder(string);
    for (int i : caps) {
        sb.setCharAt(i - 1, Character.toUpperCase(sb.charAt(i - 1)));
    }
    return sb.toString();
}


public static void main(String[] args) {
    int[] caps = {2, 4, 8, 16};
    System.out.println(capitalize("letters in a string", caps));
}

Upvotes: 0

l1zZY
l1zZY

Reputation: 100

Maybe you could do something like

public static String capitalize(String s, int[] array)//array would be the indexes you want to be caps.
{
  char[] stringChars = new char[s.length];
  for(int x = 0; x < stringChars.length; x++)
  {
    stringChars[x] = s.charAt(x);
  }
  String finalString;
  boolean matches;
  for(int x = 0; x < stringChars.length; x++)
  {
    for(int y = 0; y < array.length; y++)
    {
      if(array[y] == x)
        {
         matches = true;
         break;
        }
       if(matches == true)
         stringChars[x] = Character.toUppercase(stringChars[x]);
       finalString += stringChars[x];
    }
  }
  return finalString;
}

I haven't tested this code and there may be some bugs but it could work.

Upvotes: 0

MadProgrammer
MadProgrammer

Reputation: 347334

Assuming that you want to set the character at an ever increasing range of power by 2 (2, 4, 8, 16, 32, 64...), you could simply use a loop.

The problem is, String isn't mutable (it can't be changed) and you should avoid String concatenation within loops where possible (okay, in your case, it's probably not a big deal, but it's still good practice).

To that end, you could either convert the String to a char array (String#toCharArray()) or use a StringBuilder, for example...

String text = "letters in a string";
int index = 2;
StringBuilder sb = new StringBuilder(text);
while (index < sb.length()) {
    sb.setCharAt(index - 1, Character.toUpperCase(sb.charAt(index - 1)));
    index *= 2;
    System.out.println(index);
}

System.out.println(sb.toString());

Which outputs lEtTers in a stRing

Upvotes: 3

Forseth11
Forseth11

Reputation: 1438

Yes you can do this without hard coding the offset. Here is an example:

int[] toCaps = new int[]{2, 4, 8, 16};
String input = "letters in a string";
String newString = "";
for(int i = 0; i < input.length(); i++){
    boolean b = false;
    for(int j : toCaps){
        if(i == (j-1)){//Subtract 1 since the indexing starts at 0.
            b = true;
        }
    }
    if(b){
        newString += Character.toUpperCase(input.charAt(i));
    }else{
        newString += input.charAt(i);
    }
}
System.out.println(newString);

Now what ever numbers are in the toCaps array will be the location of the string which is converted to uppercase.

Upvotes: 0

Related Questions