Vijay Innamuri
Vijay Innamuri

Reputation: 4372

Java split string with combinations

My input string is

element1-element2-element3-element4a|element4b-element5-

Expected output is

element1-element2-element3-element4a-element5-
element1-element2-element3-element4b-element5-

So the dash (-) is the delimiter and the pipe (|) indicates two alternative elements for a position.

I am able to generate combinations for input containing a single pipe:

ArrayList<String> finalInput = new ArrayList<String>();
String Input = getInputPath();
StringBuilder TempInput = new StringBuilder();
if(Input.contains("|")) {
    String[] splits = Input.split("\\|", 2);
    TempInput.append(splits[0]+"-"+splits[1].split("-", 2)[1]);
    finalInput.add(TempInput.toString());
    TempInput = new StringBuilder();
    String[] splits1 = new StringBuilder(Input).reverse().toString().split("\\|", 2);
    finalInput.add(TempInput.append(splits1[0]+"-"+splits1[1].split("-", 2)[1]).reverse().toString());              
}

But this logic fails if there are multiple pipe symbols.

Is there any efficient way to use split String with combinations?

Input:

element1-element2-element3-element4a|element4b-element5-element6a|element6b

Output:

element1-element2-element3-element4a-element5-element6a
element1-element2-element3-element4b-element5-element6a
element1-element2-element3-element4a-element5-element6b
element1-element2-element3-element4b-element5-element6b

Upvotes: 2

Views: 1735

Answers (5)

Vignesh
Vignesh

Reputation: 364

This helps to acheive the same..

public class MultiStringSplitter {
    public static void main(String arg[]) {
        String input = "a-b|c-d|e-f|g-h";
        String[] primeTokens = input.split("-");
        String[] level2Tokens = null;
        String element = "";
        String level2element = "";
        ArrayList stringList = new ArrayList();
        ArrayList level1List = new ArrayList();
        ArrayList level2List = new ArrayList();

        for (int i = 0; i < primeTokens.length; i++) {
            // System.out.print(primeTokens[i]);


            if (primeTokens[i].contains("|")) {
                level2Tokens = primeTokens[i].split("\\|");
                for (int j = 0; j < level2Tokens.length; j++) {
                    for (int k = 0; k < stringList.size(); k++) {
                        element = (String) stringList.get(k);
                        level2element = element + level2Tokens[j];
                        level2List.add(level2element);
                    }
                }
                stringList = new ArrayList();
                for (int w = 0; w < level2List.size(); w++) {
                    stringList.add(level2List.get(w));
                }
                level2List = new ArrayList();

            }
            else {
                if (stringList.size() > 0) {
                    for (int z = 0; z < stringList.size(); z++) {
                        element = (String) stringList.get(z);
                        element = element + primeTokens[i];
                        level1List.add(element);
                    }
                    stringList = new ArrayList();
                    for (int w = 0; w < level1List.size(); w++) {
                        stringList.add(level1List.get(w));
                    }
                    level1List = new ArrayList();

                }
                else {
                    element = element + primeTokens[i];
                    if (stringList.size() == 0) {
                        stringList.add(element);
                    }
                }
            }
        }

        for (int q = 0; q < stringList.size(); q++) {
            System.out.println(stringList.get(q));
        }
    }
}  

Input : a-b|c-d|e-f|g-h

Output:

    abdfh
    acdfh
    abefh
    acefh
    abdgh
    acdgh
    abegh
    acegh 

Upvotes: 0

Adriaan Koster
Adriaan Koster

Reputation: 16209

Here's my iterative solution:

import java.util.*;

public class PathParser {

    private static final String DELIMINATOR_CONCAT = "-";
    private static final String DELIMINATOR_OPTION = "|";

    private List<String> paths;
    private List<String> stack;

    private List<String> parse(final String pathSpec) {
        stack = new ArrayList<String>();
        paths = new ArrayList<String>();
        paths.add("");
        final StringTokenizer tok = createStringTokenizer(pathSpec);
        while (tok.hasMoreTokens()) {
            final String token = tok.nextToken();
            parseToken(token);
        }
        if (!stack.isEmpty()) {
            updatePaths();
        }
        return paths;
    }

    private void parseToken(final String token) {
        if (DELIMINATOR_CONCAT.equals(token)) {
            updatePaths();
        } else if (DELIMINATOR_OPTION.equals(token)) {
            // nothing to do
        } else {
            stack.add(token);
        }
    }

    private void updatePaths() {
        final List<String> originalPaths = new ArrayList<String>(paths);
        paths.clear();
        while (stack.size() > 0) {
            paths.addAll(createNewPaths(originalPaths));
        }
    }

    private List<String> createNewPaths(final List<String> originalPaths) {
        final List<String> newPaths = new ArrayList<String>(originalPaths);
        addPart(newPaths, stack.remove(0));
        addPart(newPaths, DELIMINATOR_CONCAT);
        return newPaths;
    }

    private void addPart(final List<String> paths, final String part) {
        for (int i = 0; i < paths.size(); i++) {
            paths.set(i, paths.get(i) + part);
        }
    }

    private StringTokenizer createStringTokenizer(final String pathSpec) {
        final boolean returnDelimiters = true;
        final String delimiters = DELIMINATOR_CONCAT + DELIMINATOR_OPTION;
        return new StringTokenizer(pathSpec, delimiters, returnDelimiters);
    }

    public static void main(final String[] args) {
        final PathParser pathParser = new PathParser();
        final String input = "element1-element2-element3-element4a|element4b|element4c-element5-element6a|element6b|element6c";
        System.out.println("Input");
        System.out.println(input);
        System.out.println();

        final List<String> paths = pathParser.parse(input);

        System.out.println("Output");
        for (final String path : paths) {
            System.out.println(path);
        }
    }
}

Output:

Input
element1-element2-element3-element4a|element4b-element5-element6a|element6b

Output
element1-element2-element3-element4a-element5-element6a-
element1-element2-element3-element4b-element5-element6a-
element1-element2-element3-element4a-element5-element6b-
element1-element2-element3-element4b-element5-element6b-

Upvotes: 0

Joop Eggen
Joop Eggen

Reputation: 109597

Recursion helps.

public static void main(String[] args) {
    produce("element1-element2-element3-element4a|element4b"
        + "-element5-element6a|element6b");
}

private static void produce(String input) {
    String[] sequence = input.split("-");
    String[][] elements = new String[sequence.length][];
    for (int i = 0; i < sequence.length; ++i) {
        elements[i] = sequence[i].split("\\|");
    }
    List<String> results = new ArrayList<>();
    walk(results, elements, 0, new StringBuilder());
}

private static void walk(List<String> results, String[][] elements,
        int todoIndex, StringBuilder done) {
    if (todoIndex >= elements.length) {
        results.add(done.toString());
        System.out.println(done);
        return;
    }
    int doneLength = done.length();
    for (String alternative : elements[todoIndex]) {
        if (done.length() != 0) {
            done.append('-');
        }
        done.append(alternative);
        walk(results, elements, todoIndex + 1, done);
        done.setLength(doneLength); // Undo
    }
}

The String.split method is used twice to get a navigatable String[][]. And to build a final String a StringBuilder is used.

Upvotes: 5

armnotstrong
armnotstrong

Reputation: 9065

I have write a demo for you as what I comment after your post, the code may be ugly, but it works

public class TestSplit {
    //define a stringList hold our result.
    private static List<String> stringList = new ArrayList<String>();

    //this method fork the list array when we meet a "|"
    public static void forkStringList(){
        List<String> tmpList = new ArrayList<String>();
        for(String s: stringList){
            tmpList.add(s);
        }
        stringList.addAll(tmpList);
    }

    //when we meet "|" split two elems, should add it to 
    //the string list half-half
    public static void addTowElems(String s1, String s2){
        for(int i=0;i<stringList.size()/2;i++){
            stringList.set(i,stringList.get(i)+s1);
        }
        for(int i = stringList.size()/2;i<stringList.size();i++){
            stringList.set(i,stringList.get(i)+s2);
        }
    }
    // if not meet with a "|" just add elem to everyone of the stringlist
    public static void addOneElem(String s){
        for(int i=0;i<stringList.size();i++){
            stringList.set(i,stringList.get(i)+s);
        }
    }

    public static void main(String[] argvs){
        //to make *fork*  run, we must make sure there is a "init" string 
        //which is a empty string.
        stringList.add("");
        // this is your origin string.
        String input = "a-b-c-d|e-f";
        for (String s: input.split("\\-")){
            if(s.contains("|")){
                //when meet with "|", first fork the stringlist 
                forkStringList();
                // then add them separately 
                addTowElems(s.split("\\|")[0],s.split("\\|")[1]);
            }else {
                // else just happily add the elem to every one 
                // of the stringlist
                addOneElem(s);
            }
        }
        //checkout the result, should be expected.
        System.out.println(stringList);
    }

}

Upvotes: 1

Abhyudit Jain
Abhyudit Jain

Reputation: 3748

You can use StringTokenizer in Java. Basically it makes tokens of the string.

public StringTokenizer(String str, String delim)

Here's an example:

String msg = "http://100.15.111.60:80/"; 
char tokenSeparator= ':'; 
StringTokenizer st = new StringTokenizer(msg, tokenSeparator + "");          
while(st.hasMoreTokens()) {
    System.out.println(st.nextToken());
}

Upvotes: 1

Related Questions