Script para extrair entradas selecionadas de um arquivo bibtex

11

Eu tenho um arquivo bibtex grande com muitas entradas em que cada entrada tem a estrutura geral

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

(em alguns casos, ARTICLEpode ser uma palavra diferente, por exemplo BOOK)

O que eu gostaria de fazer é escrever um script simples (de preferência apenas um script shell) para extrair entradas com o AuthorYear fornecido e colocá-las em um novo arquivo .bib.

Posso imaginar que reconheço a primeira frase de uma entrada por AuthorYear e a última pelo fechamento único }e talvez use sedpara extrair a entrada, mas não sei exatamente como fazer isso exatamente. Alguém pode me dizer como eu conseguiria isso?

Provavelmente deveria ser algo como

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

Mas isso é interrompido devido ao fechamento }do primeiro item da entrada, fornecendo assim esta saída:

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

Então, eu preciso reconhecer se esse }é o único caractere em uma linha e apenas 'sed' para de ler quando esse for o caso.

Michiel
fonte
Eu só podia modificar seu código um pouco: sed -n "/AuthorYear/,/\}$/p". Observe o $símbolo. Funciona bem, exceto que não imprime o fechamento }de um bibitem. Aliás, é sednecessário o uso de ?
Barun
@ Barun o uso de sednão é necessário, eu apenas pensei que seria a opção mais fácil. Eu descobri um código um pouco diferente: o sed -n "/AuthorYear/, /^ *\}/p"que parece fazer exatamente o que eu quero, incluindo o fechamento }e a correção de espaços, se houver algum.
Michiel

Respostas:

2

O script Python a seguir faz a filtragem desejada.

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

Pessoalmente, prefiro mudar para uma linguagem de script quando a lógica de filtragem se tornar complexa. Talvez isso tenha uma vantagem no fator de legibilidade, pelo menos.

Barun
fonte
Cuidado, existem muitas entradas com {}s aninhados . Se você puder garantir que a entrada termine com \n}, poderá parar com^}
vonbrand
8

Eu recomendaria o uso de uma linguagem com uma biblioteca BibTeX testada em batalha, em vez de reinventar a roda. Por exemplo

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

Você provavelmente terá que instalar o módulo: cpan install BibTeX::Parser

Glenn Jackman
fonte
1

Agora também temos o módulo de bibparsing Python, que permite analisar bancos de dados BibTeX com Python. Por exemplo, eu uso o seguinte script para calcular o número de autores em trabalhos colaborativos:

#!/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
fonte
1

Outra opção seria usar o bibtool.

Exemplo:

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

Confira o manual para casos específicos.

Kirk Walla
fonte
0

Este é um script Bash que lê cada linha e usa a correspondência de regex para extrair cada entrada que possui o padrão necessário em sua cabeça. Você pode chamá-lo getbibsou algo assim:

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

Para extrair todas as entradas com um ano de autor de 1989, você pode fazer:

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

Pode ter alguns problemas que ainda não testei, mas parece funcionar bem para a tarefa.


fonte
0

Apenas para ser completo, do jeito que eu descobri, não tão legal quanto alguns dos outros, mas funciona:

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

Pode ser executado a partir da linha de comando ou inserido em um script bash.

Michiel
fonte