Script per estrarre le voci selezionate da un file bibtex


11

Ho un grande file bibtex con molte voci in cui ogni voce ha la struttura generale

@ARTICLE{AuthorYear,
item = {...},
item = {...},
item = {...},
etc
}

(in alcuni casi ARTICLEpotrebbe essere una parola diversa, ad esempio BOOK)

Quello che vorrei fare è scrivere un semplice script (preferibilmente solo uno script di shell) per estrarre le voci con il dato AuthorYear e metterle in un nuovo file .bib.

Posso immaginare di poter riconoscere la prima frase di una voce di AuthorYear e l'ultima dalla chiusura singola }e forse usare sedper estrarre la voce, ma non so davvero come farlo esattamente. Qualcuno può dirmi come avrei raggiunto questo obiettivo?

Probabilmente dovrebbe essere qualcosa del genere

sed -n "/AuthorYear/,/\}/p" file.bib

Ma ciò si interrompe a causa della chiusura }nel primo elemento della voce dando così questo output:

@ARTICLE{AuthorYear,
item = {...},

Quindi ho bisogno di riconoscere se }è l'unico carattere in una riga e avere 'sed' smettere di leggere solo quando questo è il caso.


Potrei modificare solo il codice di un po ': sed -n "/AuthorYear/,/\}$/p". Nota il $simbolo. Funziona bene, tranne per il fatto che non stampa la chiusura }di un bibitem. A proposito, è sednecessario l'uso di ?
Barun,

@Barun l'uso di sednon è affatto necessario, ho solo pensato che sarebbe stata l'opzione più semplice. Ho capito un codice leggermente diverso: sed -n "/AuthorYear/, /^ *\}/p"che sembra fare esattamente quello che voglio, inclusa la chiusura }e la correzione degli spazi se ce ne sono
Michiel

Risposte:


2

Il seguente script Python esegue il filtro desiderato.

#!/usr/bin/python
import re

# Bibliography entries to retrieve
# Multiple pattern compilation from: http://stackoverflow.com/a/11693340/147021
pattern_strings = ['Author2010', 'Author2012',]
pattern_string = '|'.join(pattern_strings)
patterns = re.compile(pattern_string)


with open('bibliography.bib', 'r') as bib_file:
    keep_printing = False
    for line in bib_file:
        if patterns.findall(line):
            # Beginning of an entry
            keep_printing = True

        if line.strip() == '}':
            if keep_printing:
                print line
                # End of an entry -- should be the one which began earlier
                keep_printing = False

        if keep_printing:
            # The intermediate lines
            print line,

Personalmente, preferisco passare a un linguaggio di scripting quando la logica di filtraggio diventa complessa. Questo, forse, ha almeno un vantaggio sul fattore di leggibilità.


Attenzione, ci sono molte voci con messaggi nidificati {}. Se puoi assicurarti che l'iscrizione finisca \n}, puoi fermarti con^}
vonbrand il

8

Consiglierei di usare un linguaggio con una libreria BibTeX testata in battaglia invece di reinventare quella ruota. Per esempio

#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use BibTeX::Parser;

open my $fh, '<', $ARGV[0];
my $parser = BibTeX::Parser->new($fh);
my @authoryear;
while (my $entry = $parser->next) {
    if ($entry->parse_ok) {
        if ($entry->key eq "AuthorYear") {
            push @authoryear, $entry;
        }
    }
    else {
        warn "Error parsing file: " . $entry->error;
    }
}

# I'm not familiar with bibtex files, so this may be insufficient
open my $out, '>', "authoryear.bib";
foreach my $entry (@authoryear) {
    say $out $entry->raw_bibtex;
}

Probabilmente dovrai installare il modulo: cpan install BibTeX::Parser


1

Ora abbiamo anche il modulo bibparsing Python, che consente di analizzare i database BibTeX con Python. Ad esempio, utilizzo il seguente script per calcolare il numero di autori in articoli collaborativi:

#!/usr/bin/python
import sys
import bibtexparser as bp
with open(sys.argv[1]) as bibtex_file:
    bd = bp.load(bibtex_file)
    for art in bd.entries_dict:
    print("*********")
    ae = bd.entries_dict[art]
    print(ae[u'title'])
    auths=ae[u'author'].split(" and ")
    print(len(auths))
    print(auths[0]+" --- "+auths[-1])

1

Un'altra opzione sarebbe quella di usare bibtool.

Esempio:

bibtool -- select{$key AuthorYear”} input.bib -o output.bib

Consulta il manuale per casi specifici.


0

Questo è uno script Bash che legge ogni riga e usa la corrispondenza regex per estrarre ogni voce che ha il modello richiesto nella sua testa. Puoi chiamarlo getbibso qualcosa del genere:

#!/usr/bin/env bash
# usage: ./getbibs pattern input.bib output.bib

while read entry; do
    if [[ $entry =~ ^@.*{$1,$ ]]; then
        printf "%s\n" "$entry" >> "$3"
        while read item; do
            [[ $item =~ ^@.*$ ]] && break
            printf "%s\n" "$item" >> "$3"
        done
    fi
done < "$2"

Per estrarre tutte le voci con un anno autore del 1989 è possibile:

$ chmod +x ./getbibs
$ ./getbibs 1989 file.bib author.bib

Potrebbe avere alcuni problemi che non ho ancora testato, ma sembra funzionare bene per l'attività.


0

Solo per essere completo, il modo in cui mi sono immaginato, non bello come alcuni degli altri, ma funziona:

entries=( AuthorYear1 AuthorYear2 )
for entry in "${entries[@]}" do
     sed -n "/"${entry}"/, /^ *\}/p" refs.bib 
done

Può essere eseguito dalla riga di comando o inserito in uno script bash.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.