Reputation: 11
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
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:
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 |$
$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
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