jkitchin / org-ref

org-mode modules for citations, cross-references, bibliographies in org-mode and useful bibtex tools to go with it.
GNU General Public License v3.0
1.37k stars 244 forks source link

How to customize the format of Bibtexkey? #426

Closed zhixing2017 closed 7 years ago

zhixing2017 commented 7 years ago

When I add a reference by the command crossref-add-bibtex-entry. The bibtexkey was generated. How to change the format of the bibtexkey? Here is an example.

@article{Azmi2015-Detection Of Listeria Monocytogenes,
  author =       {Sarfuddin Azmi and Keren Jiang and Michael Stiles and Thomas
                  Thundat and Kamaljit Kaur},
  title =        {Detection Of Listeria Monocytogenes with Short Peptide Fragments
                  From Class Iia Bacteriocins As Recognition Elements},
  journal =      {ACS Combinatorial Science},
  volume =       17,
  number =       3,
  pages =        {156-163},
  year =         2015,
  doi =          {10.1021/co500079k},
  url =          {https://doi.org/10.1021/co500079k},
  DATE_ADDED =   {Wed May 3 08:53:49 2017},
}

I want to change the bibtexkey to 2015-Azmi-10.1021_co500079k. [year]-[author]-[doi] and the / was replaced by _.

Can this function be realized?

jkitchin commented 7 years ago

The key is formatted according to the settings of bibtex-autokey-* variables. I use these settings. Look at the documentation of them to see how to get the format you want. The function (bibtex-generate-autokey) does this.

(setq bibtex-autokey-year-length 4 bibtex-autokey-name-year-separator "-" bibtex-autokey-year-title-separator "-" bibtex-autokey-titleword-separator "-" bibtex-autokey-titlewords 2 bibtex-autokey-titlewords-stretch 1 bibtex-autokey-titleword-length 5)

I am not sure how easy it is to get what you want, although you could advise the autokey function to make it do something else.

zhixing2017 commented 7 years ago

Yes, the function (bibtex-generate-autokey) can work for this. But it uses the author, year and title field. How to use the DOI field? Only the DOI can keep the bibtexkey unique.

jkitchin commented 7 years ago

See the orcb-key function. You can add a function to org-ref-clean-bibtex-entry-hook that might do what you want.

zhixing2017 commented 7 years ago

Sorry, Can you give me an example? I know little emacs-lisp and regex. I do not know how to add the function (orcb) and set the function (bibtex-generate-autokey)

jagrg commented 7 years ago

With John's setup above the chances of yielding duplicate keys is already very small. In any case, here's a function that appends the doi to the key.

(defun orcb-append-doi ()
  "If entry has a DOI, append it to the key."
  (save-excursion
    (bibtex-narrow-to-entry)
    (bibtex-beginning-of-entry)
    (when (looking-at bibtex-entry-maybe-empty-head)
      (let ((key (bibtex-key-in-head))
        (doi (bibtex-autokey-get-field "doi")))
    (re-search-forward key nil t)
    (when doi
      (replace-match
       (format "%s-%s" key (replace-regexp-in-string "/" "_" doi))))))))

(add-to-list 'org-ref-clean-bibtex-entry-hook 'orcb-append-doi t)
zhixing2017 commented 7 years ago

It worked. Thanks very much. Here is a little question. I add below code into my config. Also the former function (orcb-append-doi).

  (setq bibtex-autokey-year-length 4
        bibtex-autokey-name-year-separator "-"
        bibtex-autokey-year-title-separator "_"
        bibtex-autokey-titleword-separator "-"
        bibtex-autokey-titlewords 0
        bibtex-autokey-titlewords-stretch 1
        bibtex-autokey-titleword-length 0
        bibtex-autokey-name-case-convert-function 'capitalize)

Now the format of Bibtexkey is "Name-year-DOI". I want to know how to exchange Name field and Year field . Because my other references is in the format: "year-Name-DOI", which is generated by Jabref.

jagrg commented 7 years ago

Open your bib file and run M-x org-ref-clean-bibtex-entry on any one of your previous entries. The old key should be updated.

zhixing2017 commented 7 years ago

That requires a heavy work. Not only the cite format in my org notes I need to fix, but also the name of PDFs. I have at least 2 k PDFs' names to change. Is there an easy way to change the bibtexkey in this way: YEAR-Name-DOI? If not, I will do what you say. After all, the doi has been used.

jagrg commented 7 years ago

This should clean all entries in the buffer. I'm not sure how you would rename pdfs.

(defun bibtex-clean-entries ()
  "Clean all bibtex entries in the buffer."
  (interactive)
  (goto-char (point-min))
  (let ((number 0))
    (save-restriction
      (bibtex-map-entries (lambda (_key _beg _end) (setq number (1+ number)))))
    (dotimes (i number)
      (org-ref-bibtex-next-entry 1)
      (org-ref-clean-bibtex-entry))))
zhixing2017 commented 7 years ago

The func did not work. I do not know the meaning. I'd like to this format year-name-doi, because I can sort the pdfs by years. Maybe I just use this format year-doi. Anyway, thank you.

jagrg commented 7 years ago

I'm not sure if this is the best way to do what you want, but let's see.

  1. Remove orcb-append-doi from org-ref-clean-bibtex-entry-hook.
  2. Add the code below (as well as the bibtex-clean-entries function above) to your init/.emacs file.
  3. Restart Emacs
  4. Backup your bib file now just in case
  5. Open your bib file and run M-x bibtex-clean-entries.
(defun orcb-year-author-doi ()
  "Replace bibtex key using YYYY-Author-DOI format."
  (save-excursion
    (bibtex-narrow-to-entry)
    (bibtex-beginning-of-entry)
    (when (looking-at bibtex-entry-maybe-empty-head)
      (let ((key (bibtex-key-in-head))
        (year (bibtex-autokey-get-field "year"))
        (author (bibtex-autokey-demangle-name (bibtex-autokey-get-field "author")))
        (doi (bibtex-autokey-get-field "doi")))
    (re-search-forward key nil t)
    (if (string= doi "")
        (replace-match
         (format "%s-%s"
             year
             (s-capitalize author)))
      (replace-match
       (format "%s-%s-%s"
           year
           (s-capitalize author)
           (replace-regexp-in-string "/" "_" doi))))))))

(add-to-list 'org-ref-clean-bibtex-entry-hook 'orcb-year-author-doi t)
zhixing2017 commented 7 years ago

Thank you. It worked, but a little mistake. In the fixed format, the Author name is the first name of second author. Maybe the first author or the last are better.

jagrg commented 7 years ago

I think this is a bug in the bibtex-autokey-demangle-name function.

(bibtex-autokey-demangle-name "Last, First") ; => Last
(bibtex-autokey-demangle-name "First Last") ; => Last
(bibtex-autokey-demangle-name "Last, First and Last2, First2") ; => Last
(bibtex-autokey-demangle-name "First Last and First2 Last2") ; => First2
zhixing2017 commented 7 years ago

Yes, it is. Thank you very much.

jagrg commented 7 years ago

We can create a list of last names and return the car of the list. This should work:

(car (mapcar 'bibtex-autokey-demangle-name
         (split-string "First Last and First2 Last2"
               "[ \t\n]+and[ \t\n]+"))) ; => Last
zhixing2017 commented 7 years ago

I find a func: bibtex-autokey-get-names I used this code instead of bibtex-autokey-get-field "author". It worked.

zhixing2017 commented 7 years ago

What does the car do? How can we get the last author' last name?

zhixing2017 commented 7 years ago

If I want to use the last author' last name, what should I do to the let author field in your func orcb-year-author-doi?

jagrg commented 7 years ago

Replace it with:

(author (car (last (mapcar 'bibtex-autokey-demangle-name
                       (split-string (bibtex-autokey-get-field "author")
                             "[ \t\n]+and[ \t\n]+")))))
zhixing2017 commented 7 years ago

It worked. Thank you!

zhixing2017 commented 7 years ago

How can I prevent the error while there are some ASCII characters in author's names?

jkitchin commented 7 years ago

I am not sure what you mean. What kind of error do you see?

zhixing2017 commented 7 years ago

Like the name Bühlmann, it will report an error because of "ü".

But now I have figured it out by modifying org-ref-clean-bibtex-entry-hook.

Thank you.

jdtonkin commented 6 years ago

I'm curious, has anyone found a way to rename all pdfs associated with their bib files? My naming convention of citation keys has been the same as John's, but with three title words (bibtex-autokey-titlewords 3), rather than two. I'm tempted to revert to two as long bib keys clutter my manuscripts, but have to figure out a way of doing this for the associated pdfs. I'm guessing there's a simple shell script or something that can strip text back to last "-", but some of my key's only have one title word, so it may get a bit messed up.

jkitchin commented 6 years ago

First make a backup copy of your bib file and pdf directory.

Then in your bib file, use bibtex-map-entries with a function that saves the current key, then makes a new key in the entry, and if there is an old pdf with the old key, rename it to the new key.