Order files by unconventional date in filename (PHP)
I'm working with a PHP script that allows the chronological browsing of Eggdrop-generated IRC logs. Initially, I was reading the directory contents and inserting the log names into an array based on file modification date. After a recent server move, however, the files have had their modification dates updated and the navigation is now disorderly!
The log filename structure looks like:
channel.log.dayMONTHyear.txt
for example:
shrawberry.log.08Apr2011.txt
which, for being quite human-readable, is difficult to order properly.
Since the month code is always three characters long and comes in a predictable position in the sequence, I could manually parse the nonstandard date code into a Unix timestamp, iterate through the list and add each item to an array with that timestamp, and then sort the array by that number.
But that sou开发者_如何学Pythonnds excessive.
Am I on the money, or is the solution I proposed ideal?
With Marc B.'s help, I've implemented the following:
function dateFromEggLog($string){
$month = substr($string,-11,-8);
$day = substr($string,-13,-11);
$year = substr($string,-8,-4);
for($i=1;$i<=12;$i++){
if(strtolower(date("M", mktime(0, 0, 0, $i, 1, 0))) == strtolower($month)){
$month = $i;
break;
}
}
return "$year-$month-$day";
}
function my_compare($a, $b) {
$a_date = dateFromEggLog($a);
$b_date = dateFromEggLog($b);
if ($a_date == $b_date) {
return 0;
}
$a = strtotime($a_date); // convert to PHP timestamp
$b = strtotime($b_date); // convert to PHP timestamp
return (($a < $b) ? -1 : 1);
}
This successfully sorts my logs, without needing to muck around with my array.
Your example filename doesn't match the "looks like" sample - the 'txt' and date string are reversed. but in any case, you can use the PHP usort()
function, which lets a user-defined function do the comparisons.
It may not be particularly efficient, but you'd do something like this:
function my_compare($a, $b) {
$a_date = ... extract date field from filename in $a
$b_date = ... extract date field from filename in $b
if ($a_date == $b_date) {
return 0;
}
$a = strtotime($a_date); // convert to PHP timestamp
$b = strtotime($b_date); // convert to PHP timestamp
return (($a < $b) ? -1 : 1);
}
usort($array_of_filenames, 'my_compare');
You used filemtime before? Why not use filectime now?
Why not, in your sort function, re-order channel.log.dayMONTHyear.txt
to channel.log.yyyymmdd.txt
using string manipulation, then use basic string comparison?
<?php
/* Helper stuff */
$months = Array(
"Jan" => "01", "Feb" => "02", "Mar" => "03",
"Apr" => "04", "May" => "05", "Jun" => "06",
"Jul" => "07", "Aug" => "08", "Sep" => "09",
"Oct" => "10", "Nov" => "11", "Dec" => "12"
);
/* The hard work */
function convertLogFilename($file) {
$pos = strpos($file, ".log.");
if ($pos === FALSE)
throw new Exception("Invalid log file format");
$pos += strlen(".log.");
$dd = substr($file, $pos, 2);
$mm = substr($file, $pos + 2, 3);
$yyyy = substr($file, $pos + 5, 4);
return substr($file, 0, $pos) . "$yyyy${months[$mm]}$dd.txt";
}
function sort_func($a, $b) {
return convertLogFilename($a) < convertLogFilename($b);
}
/* Your program */
$files = Array(
"channel.log.18Apr2011.txt",
"channel2.log.21Jan2002.txt"
);
usort($files, 'sort_func');
print_r($files);
?>
Output:
Array
(
[0] => channel2.log.21Jan2002.txt
[1] => channel.log.18Apr2011.txt
)
This ought to be significantly quicker than creating full date representations for each filename.
精彩评论