Java 8, how can I implement a switch statement using streams?

前端 未结 4 1678
忘掉有多难
忘掉有多难 2020-11-28 15:08

I have a text file imgui.ini containing:

[Debug]
Pos=7,79
Size=507,392
Collapsed=0

[ImGui Demo]
Pos=320,5
Size=550,680
Collapsed=0
4条回答
  •  清歌不尽
    2020-11-28 15:37

    The best way to parse such a file (without using dedicated 3rd party libraries), is via the regex API, and its front-end class Scanner. Unfortunately, the best operations to implement it via Stream API, are currently missing. Namely, Matcher.results() and Scanner.findAll(…) are not there yet. So unless we want to wait until Java 9, we have to create similar methods for a Java 8 compatible solution:

    public static Stream findAll(Scanner s, Pattern pattern) {
        return StreamSupport.stream(new Spliterators.AbstractSpliterator(
                1000, Spliterator.ORDERED|Spliterator.NONNULL) {
            public boolean tryAdvance(Consumer action) {
                if(s.findWithinHorizon(pattern, 0)!=null) {
                    action.accept(s.match());
                    return true;
                }
                else return false;
            }
        }, false);
    }
    public static Stream results(Matcher m) {
        return StreamSupport.stream(new Spliterators.AbstractSpliterator(
                m.regionEnd()-m.regionStart(), Spliterator.ORDERED|Spliterator.NONNULL) {
            public boolean tryAdvance(Consumer action) {
                if(m.find()) {
                    action.accept(m.toMatchResult());
                    return true;
                }
                else return false;
            }
        }, false);
    }
    

    Using methods with a similar semantic allows us to replace their usage with the standard API methods, once Java 9 is released and becomes commonplace.

    Using these two operations, you can parse your file using

    Pattern groupPattern=Pattern.compile("\\[(.*?)\\]([^\\[]*)");
    Pattern attrPattern=Pattern.compile("(.*?)=(.*)\\v");
    Map> m;
    try(Scanner s=new Scanner(Paths.get(context.io.iniFilename))) {
        m = findAll(s, groupPattern).collect(Collectors.toMap(
            gm -> gm.group(1),
            gm -> results(attrPattern.matcher(gm.group(2)))
                .collect(Collectors.toMap(am->am.group(1), am->am.group(2)))));
    }
    

    the resulting map m holds all information, mapping from the group names to another map holding the key/value pairs, i.e. you can print an equivalent .ini file using:

    m.forEach((group,attr)-> {
        System.out.println("["+group+"]");
        attr.forEach((key,value)->System.out.println(key+"="+value));
    });
    

提交回复
热议问题