Reputation: 107
I need to replace substrings within a string that are delimited. For example (abc),(def) should be (cba),(fed) after reversing.
I tried the following code but it gives back the string without reversing.
String s = "(abc),(cdef)";
s = s.replaceAll("\\(\\[.*?\\]\\)",
new StringBuilder("$1").reverse().toString());
Upvotes: 1
Views: 765
Reputation: 9096
Low tech approach using a stack to reverse:
public static String reverse(String s) {
StringBuilder buffer = new StringBuilder();
Stack<Character> stack = new Stack<>();
for(char c : s.toCharArray() ) {
if(Character.isLetter(c)) { stack.push(c); }
else if(c == ')') {
while (!stack.isEmpty()) { buffer.append(stack.pop()); }
buffer.append(',');
}
}
return buffer.deleteCharAt(buffer.length()-1).toString();
}
Upvotes: 1
Reputation: 9844
For a different take, here is an algorithm for performing an in-place trim of the parentheses and internal reversal of each component on a StringBuilder
. I have omitted input validation checking in favor of focusing on the core algorithm. You might want to add more input validation if you use this for real. For example, it currently throws an exception on an empty input string or a string that accidentally has a trailing ',' at the end, not followed by another string component.
public class TestReverse {
public static void main(String[] args) {
for (String arg: args) {
StringBuilder input = new StringBuilder(arg);
// Point start at first '(' and end at first ','.
int start = 0, end = input.indexOf(",");
// Keep iterating over string components as long as we find another ','.
while (end > 0) {
// Trim leading '(' and readjust end to keep it pointing at ','.
input.deleteCharAt(start);
end -= 1;
// Trim trailing ')' and readjust end again to keep it pointing at ','.
input.deleteCharAt(end - 1);
end -= 1;
// Reverse the remaining range of the component.
reverseStringBuilderRange(input, start, end - 1);
// Point start at next '(' and end at next ',', or -1 if no ',' remaining.
start = end + 1;
end = input.indexOf(",", start);
}
// Handle the last string component, which won't have a trailing ','.
input.deleteCharAt(start);
input.deleteCharAt(input.length() - 1);
reverseStringBuilderRange(input, start, input.length() - 1);
System.out.println(input);
}
}
private static void reverseStringBuilderRange(StringBuilder sb, int start, int end) {
for (int i = start, j = end; i < j; ++i, --j) {
char temp = sb.charAt(i);
sb.setCharAt(i, sb.charAt(j));
sb.setCharAt(j, temp);
}
}
}
> javac TestReverse.java && java TestReverse '(abc),(def)' '(foo),(bar),(baz)' '(just one)'
cba,fed
oof,rab,zab
eno tsuj
Upvotes: 0
Reputation: 1763
Another alternative if you are using Java 8:
String s = "(abc),(cdef),(ghijklm)";
Pattern pattern = Pattern.compile("[a-z]+");
Matcher matcher = pattern.matcher(s);
List<String> reversedStrings = new ArrayList<>();
while(matcher.find()){
reversedStrings.add(new StringBuilder(matcher.group()).reverse().toString());
}
reversedStrings.forEach(System.out::print);
Upvotes: 1
Reputation: 15490
An alternative:
String s = "(abc),(cdef),(ghij)", res = "";
Matcher m = Pattern.compile("\\((.*?)\\)").matcher(s);
while(m.find()){
res += "(" + new StringBuilder(m.group(1)).reverse().toString() + "),";
}
if(res.length() > 0)
res = res.substring(0,res.length()-1);
System.out.println(res);
Prints:
(cba),(fedc),(jihg)
Upvotes: 1