Sorting substrings within substrings

1.1k Views Asked by At

I’m viewing a log of file names and the times they were last modified in a specified day. Its contents look like:

(comment:file_02389.txt,lastmodified:Wed Oct 10 19:10:49)
(comment:file_02342.txt,lastmodified:Wed Oct 10 17:16:08)
(comment:file_02315.txt,lastmodified:Wed Oct 10 18:45:12)
(comment:file_02344.txt,lastmodified:Wed Oct 10 08:31:01)

The log is given as a single String with no line breaks. I want to parse the String to find the file which was most recently modified, i.e., has the latest date so file_02389.txt in this case. The character length of each “comment” is constant though hypothetically could change in the future and the file names won’t be unique if the same file is modified more than once.

Is there a most extensible/maintainable way of finding the most recent file? Execution time and memory aren't are as important factors. The main concern is that a beginner programmer can understand and work with the code.

My first thought was to split the String into a List that can be sorted with a custom Comparator. I consider this to be simple but not extensible:

{//given String log
...
//setup
List<String> temp = Arrays.asList(log.trim().split("\\(comment\\:")); //too complex for one line?
//the first entry is blank so it must be removed else a substring() call will fail
if(temp.get(0).equals(""))
    temp.remove(0);
int period = full.get(0).indexOf('.');
int colon = full.get(0).indexOf(':');

//process
Collections.sort(temp, DATE);
return test.get(test.size()-1).substring(0, period)) //last entry is the most recent
}

public final Comparator<String> DATE = new Comparator<String>()
{
public int compare(String s1, String s2)
    {
        return s1.substring(28).compareTo(s2.substring(28));
    } 
};

It works but uses substrings that depend on the line length and a Comparator that is only useful in this single case. I dislike the use of .split and then having to remove the first entry but I want to avoid a true and hard to understand regex if that is an alternative. Treating the dates as Strings instead of comparing as Integers or date objects seems undesirable but saves lines of code.

I currently use a sorted map that avoids creating a single-use Comparator with a random-looking number but a specialized map seems rather complex for what I’m trying to do. I still think it’s better than creating one array for the file names, another for the times, then a third to copy the times so the times array can be sorted and its last value compared with the corresponding index in the copy.

{
...
//same setup as before
//process
//key is time, value is file name
SortedMap<String, String> map = new TreeMap<String, String>();
for(String s : temp)
    map.put(s.substring(colon+1), s.substring(0, period));
//the value to which the last key is mapped is guaranteed to be the most recent file
return map.get(map.lastKey()); //too complex for one line?
}
2

There are 2 best solutions below

1
On BEST ANSWER

Would something like this work? Basically parsing the date out of each line, building a collection of "Pair" objects so I can then sort the collection based on the Date.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;


public class Parse {

    /**
     * @param args
     * @throws ParseException 
     */
    public static void main(String[] args) throws ParseException {
        StringBuilder sb = new StringBuilder();
        sb.append("(comment:file_02389.txt,lastmodified:Wed Oct 10 19:10:49)").append("\n");
        sb.append("(comment:file_02342.txt,lastmodified:Wed Oct 10 17:16:08)").append("\n");
        sb.append("(comment:file_02315.txt,lastmodified:Wed Oct 10 18:45:12)").append("\n");
        sb.append("(comment:file_02344.txt,lastmodified:Wed Oct 10 08:31:01)").append("\n");

            //create a date format that can parse dates formatted in the file
        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss");

            //read the file into an array of lines (or read one line at a time)
        String[] lines = sb.toString().split("\n");

            //create an array of pair objects to hold the line as well as the date
        List<Pair> list = new ArrayList<Pair>();


        for(int i=0;i<lines.length;i++){
                    //get the date component of the line
            String dateString = lines[i].substring(lines[i].length()-20, lines[i].length()-1);

            Pair pair = new Pair();
            pair.date = sdf.parse(dateString); 
            pair.line = lines[i];
            list.add(pair);
        }
        Collections.sort(list);
        System.out.println(list.get(list.size()-1).line);
    }
}
class Pair implements Comparable<Pair>{

    public Date date;
    public String line;

    @Override
    public int compareTo(Pair o) {
        return date.compareTo(o.date);
    }

}
3
On

I am interested in what others will suggest but my first instinct would be turn your original string into a json array (with a few replace queries). You could then deserialize that json and obtain right away a list of object instances, each with two properties, comments and date.

You could have a comparator for these objects to order the list the way you want it.