1

Hi I have a large library of entries, and I'd like to split it up so there is a single .bib file for each entry. This seems to be the easiest and least error-prone way of importing them into R (as opposed to doing all of this inside R)

so for example:

@Article{     king2012cem,
  author    = {Iacus, Stefano M. and King, Gary and Porro, Giuseppe},
  title     = {Causal Inference without Balance Checking: {Coarsened}
          Exact Matching},
  number    = {1},
  pages     = {1-24},
  source    = {Crossref},
  timestamp = {2021-06-10},
  year      = {2012}
}

@Book{        koskinen2012ergm,
  author    = {Johan Koskinen, Dean Lusher, Garry Robins},
  title     = {Exponential Random Graph Models for Social Networks},
  subtitle  = {Theory, Methods, and Applications},
  source    = {Crossref},
  year      = {2012}
}

would each get their own .bib file, ideally named after their citekeys, so king2012cem.bib and koskinen2012ergm.bib.

I've looked at the manual for bibtool and biber to no avail. I could probably fix some regex to do it, but I'd rather use a tried-and-tested tool for it.

Thank you,

4
  • 3
    you could easily do this with perl etc splitting on @ but how would you use the split files, it would be hard to use them from latex? Commented Feb 14, 2022 at 22:36
  • 3
    Suppose your bibliography has 30 entries, each stored in separate bib bile. What are you trying to gain by having to list 30 separate files in the argument of \addbibresource (if using biblatex) or \bibliography (if using bibtex)?
    – Mico
    Commented Feb 14, 2022 at 23:25
  • 1
    I have some matlab codes to apply and verify some standards in my bibfiles and also to get all citations from them, but I've never thought about splitting all of them. If your files are standardized, I mean thing like '@' to open the entry and '}' alone to close it, it is not hard to write a code in your favorite program language to perform this task, if not standardized, or make it standard or a more complex code will have to be written. I must agree with Mico and ask why would it be more useful/practical/simple/flexible fro anyone?
    – FHZ
    Commented Feb 15, 2022 at 4:02
  • I want to import them into R, and after trying to split them from within R, doing it thru the terminal seems to be the best option. I'm doing a litterary review of a (to me) new research field, and I want to take all the articles and snowball my way through the articles that cites them and are cited by them, scrape the abstract from Scopus, use topic modelling and word2vec to cluster them into sub-fields so I can get an overview of the field.
    – emilBeBri
    Commented Feb 15, 2022 at 5:19

2 Answers 2

2

If you're working in R, you might want to parse the data in the .bib file as a native R object, bypassing the need to create a file for each bib item. I've created a gist showing the R code for that here: https://gist.github.com/jmclawson/def66ac8635db9c6131c3f3ae092f6e5

And here's a screenshot of the resulting data.frame: enter image description here

3
  • Hey! I started working on something like that myself, but I think using a lapply/purrr::map to read in each entry separately and then rbindlist would save a lot of data wrangling code. But now you have already done it, I say thanks! I'll try it out tomorrow
    – emilBeBri
    Commented Feb 15, 2022 at 20:19
  • Text wrangling is one of the things I do most often in R, which I use for text analysis, so the explicit code made more sense to me than the efficiency of purrr mapping. (I really need to get better at that!)
    – jmclawson
    Commented Feb 15, 2022 at 21:05
  • 1
    Hey nice, very cool! I felt like doing it myself if only to get it completely under the skin, using my own prefered tools of CLI, data.table and purrr. but the result is the same, so ppl can see different ways of doing it. You should check out bibtool as a way of standadising your bibfile as I show below, then you can always make it into the format that fits your R code! and yes, purrr is great, you'll love it I'm sure
    – emilBeBri
    Commented Feb 16, 2022 at 19:35
0

Ok I got the answer myself, here it is:

using bibtool and bib2bib (from the bibtex2html), I split it up, and as a bonus is the R code for making a data.frame with all entries.

the -- 'print(xxx)' in bibtool is very useful formatting from bibtool (see the manual p. 27), which makes it possible to format a .bib in a completely standardised way, making sure everything is as it should be. unfortunately, the standard option is to break lines with \n at 77 chars and use tabs for alignment, which is not useful for parsing into R (long abstracts, titles etc).

# first make list of all entries for the loop
bib2bib -oc all-entries-list.bib  --no-comment library.bib

# then loop thru them
for xkey in $(cat all-entries-list.bib); do
  bibtool '--select{"^'$xkey'$"}' -i library.bib -o path/to/dir/"$xkey.bib" -- 'print.use.tab = {0}' -- 'print.line.length = {999999999}' 
done

and here is the code in R

# wd and libs
setwd('some/path/to/bibtex-entries')
library(fs)
library(data.table)
library(purrr)

# get all entries
fil1 <- dir_ls('input/singles-entries/work-bibliotek-entries/', regex='\\.bib')

clean_entries <- function(.x) {
        # .x <- fil1$path[[72]]; .x     
        # .x <- fil1[[72]]; .x      
        # .x <- fil1$path[[36]]; .x     
    # read lines and remove non-fields 
    x1 <- data.table(v1=readLines(.x)) %>% .[v1 %ilike% '@|=']
    # split into variabel name and variabel content
    # x1[,  (c('field', 'value')) := tstrsplit(v1, '^=+?')]
    x1[,  (c('field', 'value')) := tstrsplit(v1, '=(?= {)', perl=T)]
    x1[field %flike% '@', `:=` (
                field = 'entry-type',
                value = gsub('^@([A-Za-z]+).*$', '\\1',  v1))]

    # remove curlies and ending , from last line 
    x1[, value := gsub('(^[ ])\\{(.*)', '\\1\\2',  value)]
    x1[, value := gsub('(.+)\\},*$', '\\1',  value)]

    x2 <- data.table(x1$value) %>% data.table::transpose()  
    setnames(x2, x1$field)  
    x2
     # names(x2)
    # v(x2)  
}

# use safely() to run tru all of them and capture output or error without stopping 
bib1 <- map(fil1, safely(clean_entries))
map(bib1, 'error') %>% keep(~ !is.null(.x)) 

# rbind the list, with the name of the list element as column called 'citeky'
bib2 <- rbindlist( map(bib1, 'result'), idcol='citekey', fill=TRUE)
# remove path from citekey column
bib2[, citekey := gsub('^.*/(.*).bib$', '\\1', citekey)]

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .