Bibtex dosyasından seçilen girdileri ayıklamak için komut dosyası


11

Her girişin genel yapıya sahip olduğu birçok giriş içeren büyük bir bibtex dosyası var

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

(bazı durumlarda ARTICLEfarklı bir kelime olabilir örneğin BOOK)

Ne yapmak istiyorum verilen AuthorYear ile girişleri ayıklamak ve yeni bir .bib dosyasına koymak için basit bir komut dosyası (tercihen sadece bir kabuk komut dosyası) yazmaktır.

Bir girişin ilk cümlesini AuthorYear'ın son cümlesini tek bir kapanışla tanıyabildiğimi }ve belki de sedgirişi çıkarmak için kullandığımı hayal edebilirim , ancak bunu tam olarak nasıl yapacağımı bilmiyorum. Birisi bana bunu nasıl başaracağımı söyleyebilir mi?

Muhtemelen böyle bir şey olmalı

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

Ancak bu }, girişin ilk öğesindeki kapanış nedeniyle durur ve böylece bu çıktıyı verir:

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

Bu yüzden }bir satırdaki tek karakter olup olmadığını ve bu durumda sadece 'sed' okumayı bırakıp bırakmadığımı bilmeliyim.


Ben sadece kod biraz değiştirebilir: sed -n "/AuthorYear/,/\}$/p". $Sembolü not edin . }Bir bibitemin kapanışını yazdırmaması dışında iyi çalışır . Btw, kullanımı sedgerekli mi?
Barun

@Barun kullanımı sedhiç gerekli değil, sadece en kolay seçenek olacağını düşündüm. Biraz farklı bir kod çözdüm: sed -n "/AuthorYear/, /^ *\}/p"Tam olarak istediğim şeyi yapıyor gibi görünüyor, }varsa boşluklar için kapatma ve düzeltme
Michiel

Yanıtlar:


2

Aşağıdaki Python betiği istenen filtrelemeyi yapar.

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

Şahsen, filtreleme mantığı karmaşıklaştığında bir betik diline geçmeyi tercih ederim. Belki de en azından okunabilirlik faktörüne bir avantajı vardır.


Dikkatli olun, iç içe geçmiş çok sayıda giriş var {}. Eğer sizinle giriş uçlarını sağlayabilirsiniz \n}, sen ile durdurabilirsiniz^}
vonbrand

8

Bu tekerleği yeniden icat etmek yerine savaşta test edilmiş BibTeX kütüphanesi ile bir dil kullanmanızı tavsiye ederim. Örneğin

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

Muhtemelen modülü kurmanız gerekecektir: cpan install BibTeX::Parser


1

Şimdi de Python ile BibTeX veritabanlarını analiz etmeyi sağlayan Python bibparsing modülümüz var. Örneğin, ortak çalışma belgelerindeki yazar sayısını hesaplamak için aşağıdaki komut dosyasını kullanıyorum:

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

Başka bir seçenek bibtool kullanmak olacaktır.

Misal:

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

Özel durumlar için kılavuza bakın.


0

Bu, her satırı okuyan ve kafasında gerekli paterni olan her girdiyi çıkarmak için normal ifade eşleşmesini kullanan bir Bash betiğidir. Buna getbibsfalan diyebilirsiniz :

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

1989 yazar yılı ile tüm girişleri çıkarmak için şunları yapabilirsiniz:

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

Henüz test etmediğim bazı sorunlar olabilir, ancak görev için iyi çalışıyor gibi görünüyor.


0

Sadece tam olarak söylemek gerekirse, kendimi anladım, diğerleri gibi hoş değil, ama işe yarıyor:

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

Komut satırından çalıştırılabilir veya bir bash komut dosyasına yerleştirilebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.