user1579878
user1579878

Reputation: 107

Reverse multiple strings between delimiters

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

Answers (4)

David Soroko
David Soroko

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

Chris Nauroth
Chris Nauroth

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

krackmoe
krackmoe

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

elias
elias

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

Related Questions