Script pour extraire les entrées sélectionnées d'un fichier bibtex

11

J'ai un gros fichier bibtex avec de nombreuses entrées où chaque entrée a la structure générale

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

(dans certains cas, ARTICLEpeut être un mot différent, par exemple BOOK)

Ce que je voudrais faire, c'est écrire un script simple (de préférence juste un script shell) pour extraire les entrées avec AuthorYear donné et les mettre dans un nouveau fichier .bib.

Je peux imaginer que je peux reconnaître la première phrase d'une entrée par AuthorYear et la dernière par la fermeture unique }et peut-être utiliser sedpour extraire l'entrée, mais je ne sais pas vraiment comment faire exactement. Quelqu'un peut-il me dire comment j'y arriverais?

Cela devrait probablement être quelque chose comme

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

Mais cela s'arrête en raison de la fermeture }du premier élément de l'entrée, donnant ainsi cette sortie:

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

J'ai donc besoin de reconnaître si le }est le seul caractère sur une ligne et de ne lire «sed» que lorsque c'est le cas.

Michiel
la source
Je ne pouvais modifier votre code un peu: sed -n "/AuthorYear/,/\}$/p". Notez le $symbole. Cela fonctionne très bien, sauf qu'il n'imprime pas la fermeture }d'un bibitem. Btw, est-ce que l'utilisation de sednécessaire?
Barun
@Barun, l'utilisation de sedn'est pas du tout nécessaire, je pensais que ce serait l'option la plus simple. J'ai trouvé un code légèrement différent: sed -n "/AuthorYear/, /^ *\}/p"qui semble faire exactement ce que je veux, y compris la fermeture }et la correction des espaces s'il y en a
Michiel

Réponses:

2

Le script Python suivant effectue le filtrage souhaité.

#!/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,

Personnellement, je préfère passer à un langage de script lorsque la logique de filtrage devient complexe. Cela a peut-être un avantage sur le facteur de lisibilité au moins.

Barun
la source
Attention, il y a beaucoup d'entrées avec {}s imbriqués . Si vous pouvez vous assurer que l'entrée se termine avec \n}, vous pouvez vous arrêter avec^}
vonbrand
8

Je recommanderais d'utiliser un langage avec une bibliothèque BibTeX testée au combat au lieu de réinventer cette roue. Par exemple

#!/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;
}

Vous devrez probablement installer le module: cpan install BibTeX::Parser

glenn jackman
la source
1

Maintenant, nous avons également le module de bibparsing Python, qui permet d'analyser les bases de données BibTeX avec Python. Par exemple, j'utilise le script suivant pour calculer le nombre d'auteurs dans des articles collaboratifs:

#!/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])
wzab
la source
1

Une autre option serait d'utiliser bibtool.

Exemple:

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

Consultez le manuel pour les cas spécifiques.

Kirk Walla
la source
0

Il s'agit d'un script Bash qui lit chaque ligne et utilise la correspondance regex pour extraire chaque entrée qui a le modèle requis dans sa tête. Vous pouvez l'appeler getbibsou quelque chose:

#!/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"

Pour extraire toutes les entrées avec un auteur de 1989, vous pouvez faire:

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

Il peut y avoir des problèmes que je n'ai pas encore testés, mais cela semble fonctionner correctement pour la tâche.


la source
0

Juste pour être complet, la façon dont je me suis compris, pas aussi sympa que certains des autres, mais ça marche:

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

Il peut être exécuté à partir de la ligne de commande ou placé dans un script bash.

Michiel
la source