Leo
Leo

Reputation: 11

How to find the index of the first and second Uppercase Letter in a string?

If there is an input of string s. I want to loop through the whole string and break the string into smaller strings, with the string starting with an Uppercase letter and ending with an integer. For example, if the string s = "X32Y"----> the substring would be X32 and 'Y'. I have found the first time it encounters an uppercase letter, which is int a, but I'm stuck on how to find the next upper case which is for example Y. I currently used a+1, which set the end as the first time it encounters an uppercase +1. which would result in X3 instead of X32. Can someone please help find a way to find the next Uppercase? In such a way that "AX32Y" become ["A", "X32", "Y"]. Please disregard the "A1". comment, that is unnecessary, "A" is what I want.

public String Password(String s) {
    for (int i = 0; i < s.length(); i++) {
        if (Character.isUpperCase(s.charAt(i))) {
            int a = s.indexOf(s.charAt(i));
            System.out.println(s.substring(a, ** a + 1 ** ));
        }
    }
}

Upvotes: 0

Views: 1555

Answers (2)

Nowhere Man
Nowhere Man

Reputation: 19565

String::indexOf is not too helpful here because it requires a specific value which is sought (e.g. in the given example it would be str.indexOf('Y')). So if a plain iteration by the characters in the string is allowed, it should be done this way:

  1. for current char, check if it is an upper case letter
  2. if yes, pickup the digits until they end or end of the string occurs

Update

There was an update in the comments to the @Joakim Danielson's answer that a suffix 1 needs to be added to single letters, and a regular expression also allows to provide this preprocessing using String::replaceAll and a lookahead (?=):
s = s.replaceAll("([A-Z])(?=\\D|$)", "$11");

  • ([A-Z]) find a group consisting of a single capital letter
  • (?=\\D|$) ...followed by NOT a digit OR at the end of the string |$
  • and replace with the first group $1 followed by 1
String s = "ABC123QX32Y24Z";
s = s.replaceAll("([A-Z])(?=\\D|$)", "$11");
System.out.println("inserted 1 between letters: " + s);

Then the preprocessed input can be efficiently split into LetterDigits parts using regular expressions:

String[] parts = Pattern.compile("[A-Z]\\d+").matcher(s)
    .results()
    .map(MatchResult::group)
    .toArray(String[]::new);

System.out.println("after regexp: " + Arrays.toString(parts));

Output

inserted 1 between letters: A1B1C123Q1X32Y24Z1
after regexp: [A1, B1, C123, Q1, X32, Y24, Z1]

Similar solution based on iterating the string and collecting the parts into an ArrayList could look like this:

List<String> parts2 = new ArrayList<>();
String part = "";
for (int i = 0, n = s.length(); i < n; i++) {
    char c = s.charAt(i);
    if (Character.isLetter(c) && Character.isUpperCase(c)) {
        boolean digitFound = false;
        for (int j = i + 1; j < n; j++) {
            char d = s.charAt(j);
            if (Character.isDigit(d)) {
                if (!digitFound) {
                    digitFound = true;
                    part += c;
                }
                part += d;
            } else {
                if (digitFound && part.length() > 0) {
                    parts2.add(part);
                    System.out.println(part);
                }
                part = "";
                i = j - 1;
                break;
            }
        }
        if (part.length() > 0) {
            parts2.add(part);
            System.out.println(part);
            part = "";            
        }
    }
}
System.out.println("loop: " + parts2);

Output for the same input String s:

A1
B1
C123
Q1
X32
Y24
Z1
loop: [A1, B1, C123, Q1, X32, Y24, Z1]

Upvotes: 1

Joakim Danielson
Joakim Danielson

Reputation: 51993

The problem is that you are trying to do all at once, without keeping track of state (searching for uppercase or not) and without some variable holding the string you are building.

It's hard to post an exact answer since the requirements aren't very clear, can the string contain other characters than uppercase letters and numbers, what happens if there are two uppercase letters in a row etc?

But just to show you the general idea here is a solution that works for the string "X32Y"

public String password(String input) {
  StringBuilder builder = null;

  for (int i = 0; i < input.length(); i++) {
    char c = input.charAt(i);

    if (Character.isUpperCase(c)) {
      if (builder == null) { // Start building a new string
        builder = new StringBuilder();          
      } else { // This is the upppercase "after" the string, return what we have
        return builder.toString();
      }
    } // There might be an else here depending on the requirements but we add anything
      // else to the string we are building

    if (builder != null) {
      builder.append(c);
    }
  }

  //If we reach this far return what we got or an empty string
  return builder == null ? "" : builder.toString();
}

Upvotes: 1

Related Questions