Finding a string in a text file using Java 8

I have a long text file that I want to read and extract some data from it. Using JavaFX and FXML, I am using FileChooser to upload a file to get the file path. My .java controller has this:

private void handleButtonAction(ActionEvent event) throws IOException {
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt");
        fileChooser.getExtensionFilters().add(extFilter);
        File file = fileChooser.showOpenDialog(stage);
        System.out.println(file);
         stage = (Stage) button.getScene().getWindow();


    }

      

Example of a text file: Note that some of the contents of the file are split between two lines. for example -Ba \ 10.10.10.3 is part of the first line.

net ip-interface create 10.10.10.2 255.255.255.128 MGT-1 -Ba \
10.10.10.3
net ip-interface create 192.168.1.1 255.255.255.0 G-1 -Ba \
192.168.1.2 
net route table create 10.10.10.5 255.255.255.255 10.10.10.1 -i \
MGT-1
net route table create 10.10.10.6  255.255.255.255 10.10.10.1 -i \
MGT-1

      

I'm looking for a way to search this file () and output the following:

MGT-1 ip-interface 10.10.10.2 
MGT-1 Backup ip-interface 10.10.10.3
G-1 ip-interface 192.168.1.1
G-1 Backup Ip-interface 192.168.1.2
MGT-1 route 10.10.10.5 DFG 10.10.10.1
MGT-1 route 10.10.10.6 DFG 10.10.10.1

      

+3


source to share


1 answer


You can of course read the input file as a stream of lines using BufferedReader.lines

or Files.lines

. The tricky thing here, however, is how to deal with the tail "\"

. There are several possible solutions. You can write your own Reader

that wraps the existing one Reader

and simply ignores the slash followed by EOL. Alternatively, you can write a custom Iterator

or Spliterator

that takes a stream BufferedReader.lines

as input and handles that case. I would suggest using my StreamEx library which already has a method for such tasks called collapse

:

StreamEx.ofLines(reader).collapse((a, b) -> a.endsWith("\\"), 
                                  (a, b) -> a.substring(0, a.length()-1).concat(b));

      

The first argument is a predicate that applies to two adjacent strings and must return true if the strings are to be concatenated. The second argument is the function that actually concatenates the two lines (we break the forward slash through substring

and then concatenate the next line).



Now you can just split the string by space and convert it to one or two output strings as per your task. It is better to do this in a separate method. All code:

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import javax.util.streamex.StreamEx;

public class ParseFile {
    static Stream<String> convertLine(String[] fields) {
        switch(fields[1]) {
        case "ip-interface":
            return Stream.of(fields[5]+" "+fields[1]+" "+fields[3],
                             fields[5]+" Backup "+fields[1]+" "+fields[7]);
        case "route":
            return Stream.of(fields[8]+" route "+fields[4]+" DFG "+fields[6]);
        default:
            throw new IllegalArgumentException("Unrecognized input: "+
                                               String.join(" ", fields));
        }
    }

    static Stream<String> convert(Reader reader) {
        return StreamEx.ofLines(reader)
                .collapse((a, b) -> a.endsWith("\\"), 
                          (a, b) -> a.substring(0, a.length()-1).concat(b))
                .map(Pattern.compile("\\s+")::split)
                .flatMap(ParseFile::convertLine);
    }

    public static void main(String[] args) throws IOException {
        try(Reader r = new InputStreamReader(
            ParseFile.class.getResourceAsStream("test.txt"))) {
            convert(r).forEach(System.out::println);
        }
    }
}

      

+4


source







All Articles