Tập lệnh để trích xuất các mục được chọn từ tệp bibtex


11

Tôi có một tệp bibtex lớn với nhiều mục trong đó mỗi mục có cấu trúc chung

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

(trong một số trường hợp ARTICLEcó thể là một từ khác nhau, vd BOOK)

Những gì tôi muốn làm là viết một tập lệnh đơn giản (tốt nhất chỉ là tập lệnh shell) để trích xuất các mục với AuthorYear đã cho và đặt chúng vào tập tin .bib mới.

Tôi có thể tưởng tượng rằng tôi có thể nhận ra câu đầu tiên của một mục nhập bởi AuthorYear và câu cuối cùng bằng cách đóng một lần duy nhất }và có thể sử dụng sedđể trích xuất mục đó, nhưng tôi thực sự không biết làm thế nào để thực hiện điều này một cách chính xác. Ai đó có thể cho tôi biết làm thế nào tôi sẽ đạt được điều này?

Nó có lẽ nên là một cái gì đó như

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

Nhưng điều đó dừng lại do việc đóng }trong mục đầu tiên của mục nhập, do đó cho đầu ra này:

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

Vì vậy, tôi cần phải nhận ra liệu đó có phải }là ký tự duy nhất trong một dòng hay không và chỉ có 'sed' ngừng đọc khi gặp trường hợp này.


Tôi chỉ có thể sửa đổi mã của bạn một chút : sed -n "/AuthorYear/,/\}$/p". Lưu ý $ký hiệu. Nó hoạt động tốt, ngoại trừ việc nó không in kết thúc }một bibitem. Btw, là sử dụng sedcần thiết?
Barun

@Barun việc sử dụng sedkhông cần thiết chút nào, tôi chỉ nghĩ đó sẽ là lựa chọn dễ nhất. Tôi đã tìm ra một mã hơi khác: sed -n "/AuthorYear/, /^ *\}/p"dường như thực hiện chính xác những gì tôi muốn, bao gồm cả việc đóng }và sửa lỗi cho khoảng trắng nếu có bất kỳ
Michiel

Câu trả lời:


2

Kịch bản Python sau đây thực hiện lọc mong muốn.

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

Cá nhân, tôi thích chuyển sang ngôn ngữ kịch bản khi logic lọc trở nên phức tạp. Điều đó, có lẽ, có một lợi thế về yếu tố dễ đọc ít nhất.


Cẩn thận, có rất nhiều mục với {}s lồng nhau . Nếu bạn có thể đảm bảo mục nhập kết thúc bằng \n}, bạn có thể dừng lại với^}
vonbrand

8

Tôi sẽ khuyên bạn nên sử dụng ngôn ngữ có thư viện BibTeX được thử nghiệm chiến đấu thay vì phát minh lại bánh xe đó. Ví dụ

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

Bạn có thể sẽ phải cài đặt mô-đun: cpan install BibTeX::Parser


1

Bây giờ chúng tôi cũng có mô-đun bibparsing Python, cho phép phân tích cơ sở dữ liệu BibTeX với Python. Ví dụ: tôi sử dụng tập lệnh sau để tính số lượng tác giả trong các bài viết cộng tác:

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

Một lựa chọn khác là sử dụng bibtool.

Thí dụ:

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

Kiểm tra hướng dẫn cho các trường hợp cụ thể.


0

Đây là một tập lệnh Bash đọc từng dòng và sử dụng kết hợp regex để trích xuất từng mục có mẫu được yêu cầu trong đầu. Bạn có thể gọi nó getbibshoặc một cái gì đó:

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

Để trích xuất tất cả các mục có năm tác giả 1989, bạn có thể làm:

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

Nó có thể có một số vấn đề mà tôi chưa thử nghiệm, nhưng nó có vẻ hoạt động tốt cho nhiệm vụ.


0

Chỉ cần hoàn thành, cách tôi tự nhận ra, không đẹp như một số người khác, nhưng nó hoạt động:

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

Nó có thể được chạy từ dòng lệnh hoặc đặt trong tập lệnh bash.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.