Script untuk mengekstrak entri yang dipilih dari file bibtex

11

Saya memiliki file bibtex besar dengan banyak entri di mana setiap entri memiliki struktur umum

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

(dalam beberapa kasus ARTICLEmungkin kata yang berbeda misalnya BOOK)

Yang ingin saya lakukan adalah menulis skrip sederhana (sebaiknya hanya skrip shell) untuk mengekstraksi entri dengan AuthorYear yang diberikan dan meletakkannya di file .bib baru.

Saya dapat membayangkan bahwa saya dapat mengenali kalimat pertama dari sebuah entri oleh AuthorYear dan yang terakhir dengan satu penutup }dan mungkin digunakan seduntuk mengekstrak entri tersebut, tetapi saya tidak benar-benar tahu bagaimana melakukan ini secara tepat. Dapatkah seseorang memberi tahu saya bagaimana saya akan mencapai ini?

Mungkin harus seperti itu

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

Tapi itu berhenti karena penutupan }item pertama dari entri sehingga memberikan hasil ini:

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

Jadi saya perlu mengenali apakah }ini satu-satunya karakter pada satu baris dan hanya memiliki 'sed' berhenti membaca ketika ini terjadi.

Michiel
sumber
Aku hanya bisa memodifikasi kode sedikit Anda: sed -n "/AuthorYear/,/\}$/p". Perhatikan $simbolnya. Ini berfungsi dengan baik, kecuali bahwa itu tidak mencetak penutupan }bibitem. Btw, apakah sedperlu menggunakan ?
Barun
@Barun penggunaannya sedtidak perlu sama sekali, saya hanya berpikir itu akan menjadi pilihan termudah. Saya telah menemukan kode sed -n "/AuthorYear/, /^ *\}/p"yang sedikit berbeda: yang tampaknya melakukan persis apa yang saya inginkan, termasuk menutup }dan mengoreksi spasi jika ada
Michiel

Jawaban:

2

Skrip Python berikut melakukan penyaringan yang diinginkan.

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

Secara pribadi, saya lebih suka pindah ke bahasa scripting ketika logika penyaringan menjadi kompleks. Itu, mungkin, memiliki keunggulan pada faktor keterbacaan setidaknya.

Barun
sumber
Hati-hati, ada banyak entri dengan {}s bersarang . Jika Anda dapat memastikan entri berakhir dengan \n}, Anda dapat berhenti dengan^}
vonbrand
8

Saya akan merekomendasikan menggunakan bahasa dengan perpustakaan BibTeX yang telah teruji pertempuran alih-alih menciptakan kembali roda itu. Sebagai contoh

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

Anda mungkin harus menginstal modul: cpan install BibTeX::Parser

glenn jackman
sumber
1

Sekarang kita juga memiliki modul bibparsing Python, yang memungkinkan untuk menganalisis basis data BibTeX dengan Python. Misalnya saya menggunakan skrip berikut untuk menghitung jumlah penulis dalam makalah kolaboratif:

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

Pilihan lain adalah menggunakan bibtool.

Contoh:

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

Lihatlah manual untuk kasus-kasus tertentu.

Kirk Walla
sumber
0

Ini adalah skrip Bash yang membaca setiap baris dan menggunakan pencocokan regex untuk mengekstrak setiap entri yang memiliki pola yang diperlukan di kepalanya. Anda dapat menyebutnya getbibsatau sesuatu:

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

Untuk mengekstrak semua entri dengan tahun penulis 1989 Anda dapat melakukan:

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

Mungkin ada beberapa masalah yang belum saya uji, tetapi tampaknya berfungsi baik untuk tugas itu.


sumber
0

Supaya lengkap, cara saya menemukan diri sendiri, tidak sebagus beberapa yang lain, tetapi berhasil:

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

Itu bisa dijalankan dari commandline atau dimasukkan ke dalam skrip bash.

Michiel
sumber