AKIWEB
AKIWEB

Reputation: 19612

Improving the code that parses a Text File

Text File(First three lines are simple to read, next three lines starts with p)

ThreadSize:2
ExistingRange:1-1000
NewRange:5000-10000
p:55 - AutoRefreshStoreCategories  Data:Previous    UserLogged:true    Attribute:1    Attribute:16      Attribute:2060  
p:25 - CrossPromoEditItemRule      Data:New         UserLogged:false     Attribute:1      Attribute:10107   Attribute:10108
p:20 - CrossPromoManageRules       Data:Previous    UserLogged:true      Attribute:1      Attribute:10107   Attribute:10108

Below is the code I wrote to parse the above file and after parsing it I am setting the corresponding values using its Setter. I just wanted to know whether I can improve this code more in terms of parsing and other things also by using other way like using RegEx? My main goal is to parse it and set the corresponding values. Any feedback or suggestions will be highly appreciated.

private List<Command> commands;
private static int noOfThreads = 3;
private static int startRange = 1;
private static int endRange = 1000;
private static int newStartRange = 5000;
private static int newEndRange = 10000;
private BufferedReader br = null;
private String sCurrentLine = null;
private int distributeRange = 100;
private List<String> values = new ArrayList<String>();
private String commandName;
private static String data;
private static boolean userLogged;
private static List<Integer> attributeID =  new ArrayList<Integer>();

    try {
        // Initialize the system
        commands = new LinkedList<Command>();
        br = new BufferedReader(new FileReader("S:\\Testing\\Test1.txt"));

        while ((sCurrentLine = br.readLine()) != null) {
            if(sCurrentLine.contains("ThreadSize")) {
                noOfThreads = Integer.parseInt(sCurrentLine.split(":")[1]);
            } else if(sCurrentLine.contains("ExistingRange")) {
                startRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
                endRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
            } else if(sCurrentLine.contains("NewRange")) {
                newStartRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
                newEndRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
            } else {
                allLines.add(Arrays.asList(sCurrentLine.split("\\s+")));
                String key = sCurrentLine.split("-")[0].split(":")[1].trim();
                String value = sCurrentLine.split("-")[1].trim();
                values = Arrays.asList(sCurrentLine.split("-")[1].trim().split("\\s+"));
                for(String s : values) {
                    if(s.contains("Data:")) {
                        data = s.split(":")[1];
                    } else if(s.contains("UserLogged:")) {
                        userLogged = Boolean.parseBoolean(s.split(":")[1]);
                    } else if(s.contains("Attribute:")) {
                        attributeID.add(Integer.parseInt(s.split(":")[1]));
                    } else {
                        commandName = s;
                    }
                }

                Command command = new Command();
                command.setName(commandName); 
                command.setExecutionPercentage(Double.parseDouble(key));
                command.setAttributeID(attributeID);
                command.setDataCriteria(data);
                command.setUserLogging(userLogged);
                commands.add(command);

            }
        }
    } catch(Exception e) {
        System.out.println(e);
    }

Upvotes: 2

Views: 372

Answers (4)

user207421
user207421

Reputation: 310860

I would turn this inside out. Presently you are:

  1. Scanning the line for a keyword: the entire line if it isn't found, which is the usual case as you have a number of keywords to process and they won't all be present on every line.
  2. Scanning the entire line again for ':' and splitting it on all occurrences
  3. Mostly parsing the part after ':' as an integer, or occasionally as a range.

So several complete scans of each line. Unless the file has zillions of lines this isn't a concern in itself but it demonstrates that you have got the processing back to front.

Upvotes: 0

user1270627
user1270627

Reputation:

I think you should know what exactly you're expecting while using RegEx. http://java.sun.com/developer/technicalArticles/releases/1.4regex/ should be helpful.

Upvotes: 1

Xeon
Xeon

Reputation: 5989

To answer a comment:

p:55 - AutoRefreshStoreCategories  Data:Previous    UserLogged:true    Attribute:1    Attribute:16      Attribute:2060  

to parse above with regex (and 3 times Attribute:):

String parseLine = "p:55 - AutoRefreshStoreCategories  Data:Previous    UserLogged:true    Attribute:1    Attribute:16      Attribute:2060";
    Matcher m = Pattern
            .compile(
                    "p:(\\d+)\\s-\\s(.*?)\\s+Data:(.*?)\\s+UserLogged:(.*?)\\s+Attribute:(\\d+)\\s+Attribute:(\\d+)\\s+Attribute:(\\d+)")
            .matcher(parseLine);
    if(m.find()) {
        int p = Integer.parseInt(m.group(1));
        String method = m.group(2);
        String data = m.group(3);
        boolean userLogged = Boolean.valueOf(m.group(4));
        int at1 = Integer.parseInt(m.group(5));
        int at2 = Integer.parseInt(m.group(6));
        int at3 = Integer.parseInt(m.group(7));
        System.out.println(p + " " + method + " " + data + " " + userLogged + " " + at1 + " " + at2 + " "
                + at3);
    }

EDIT looking at your comment you still can use regex:

String parseLine = "p:55 - AutoRefreshStoreCategories  Data:Previous    UserLogged:true    "
            + "Attribute:1    Attribute:16      Attribute:2060";
    Matcher m = Pattern.compile("p:(\\d+)\\s-\\s(.*?)\\s+Data:(.*?)\\s+UserLogged:(.*?)").matcher(
            parseLine);
    if(m.find()) {
        for(int i = 0; i < m.groupCount(); ++i) {
            System.out.println(m.group(i + 1));
        }
    }

    Matcher m2 = Pattern.compile("Attribute:(\\d+)").matcher(parseLine);
    while(m2.find()) {
        System.out.println("Attribute matched: " + m2.group(1));
    }

But that depends if thre is no Attribute: names before "real" attributes (for example as method name - after p)

Upvotes: 0

richarbernal
richarbernal

Reputation: 1059

You can use the Scanner class. It has some helper methods to read text files

Upvotes: 0

Related Questions