Michael Chen wrote:
Thanks very much for your info, Richard. I found that somebody has
done the hack,
    http://www.tug.org/tex-archive/biblio/bibtex/contrib/misc/plainyr.bst
this .bst sorts entries by year (ascendant), author and title.   If it
is possible, would you please show me how to sort decently?
That file sorts very strangely. You may be getting the results you want, but probably not for the right reason. I just ran it on a file and, yes, I got all the articles sorted by year. But then after the articles, I got all the books, sorted by author. Fields that aren't book, inbook, proceedings, or manual will get sorted by year; but those get sorted by author or editor or whatever. If you don't have any of those, then you'll get the results you want, indeed. But you may want to try the one I sent you before:

FUNCTION {presort}
{ type$ "book" =
 type$ "inbook" =
 or
   'author.editor.sort
   { type$ "proceedings" =
       'editor.organization.sort
       { type$ "manual" =
           'author.organization.sort
           'author.sort
         if$
       }
     if$
   }
 if$
 "    "
 *
 year field.or.null sortify
 "    "
 *
 swap$ *
 title field.or.null
 sort.format.title
 *
 #1 entry.max$ substring$
 'sort.key$ :=
}

This will sort on year, ascending, unless there's no year, in which case it sorts by author or whatever.

To get a descending sort, we'll have to hack a bit more. In fact, we'll have to hack a lot more. The obvious thing to do is to subtract the year from 10000 and then sort on that. But the problem is that year is a string field, not an integer, so I think BibTeX will choke if we try to subtract it from something. And, so far as I can see, BibTeX itself provides us with no way to convert a string to an integer, though we can go the other way. We can work around this by writing a routine that will attempt to convert a 4-digit year to an integer, roughly:

INTEGERS { iterator, year.desc }

FUNCTION year.to.int {
 #0 'year.desc :=
 #1 'iterator :=
   { iterator #10000 < } #while (iterator < 10000)
   {
     iterator int.to.str$
     year purify$ = if$
        { iterator 'year.desc :=  %success...
         #10000 'iterator :=     %end the iteration
        }
        'skip$
   }
 year.desc
}

So we leave the empty string on the stack if it wasn't an integer (less than 10000). I've not tested that, and don't have time to do so right now. And note: It may take a while to do this for every entry!

So, well, we've got that. Now, we can re-write presort:

FUNCTION year.desc {
 year.to.int duplicate$ if$
   {
#10000 - int.to.str$ { "Warning: Problem with year field in " cite$ * warning$ pop$ "" %You might want to push "9999", to get yearless things at the end } }

And then, in the routine above, replace the line "year field.or.null sortify" with "year.desc". Again, I've not tested this.

Actually, a better way to do year.to.int it would be (i) to use text.length$ to check that year is four characters; (ii) use substring$ to extract the characters from year one by one, and then use chr.to.int to convert them, one at a time, to the corresponding ASCII integers; (iii) make sure we're between 48 (ASCII '0') and 57 (ASCII '9'), i.e., that we have a digit, and then substract 48 to get the actual integer; (iv) reconstruct the integer for the year from those: 1000 * year[1] + 100 * year[2], etc. That'd be much faster. But I'd better go do some actual work right now....

Richard


Reply via email to