Сценарій для вилучення вибраних записів з файлу bibtex


11

У мене великий файл bibtex з багатьма записами, де кожен запис має загальну структуру

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

(у деяких випадках ARTICLEможе бути інше слово, наприклад BOOK)

Що я хотів би зробити, це написати простий скрипт (бажано, просто сценарій оболонки), щоб витягнути записи з даним AuthorYear і помістити їх у новий .bib файл.

Я можу собі уявити, що я можу розпізнати перше речення запису від AuthorYear та останнє за одним закриттям }і, можливо, використовувати sedдля вилучення запису, але я не знаю, як це точно зробити. Хтось може сказати мені, як я цього досягну?

Напевно, це повинно бути щось на кшталт

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

Але це припиняється через закриття }першого пункту запису, таким чином даючи такий вихід:

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

Тож мені потрібно визнати, чи }є єдиним символом у рядку, і лише у такому випадку перестати читати "sed".


Я міг би змінити тільки свій код небагато: sed -n "/AuthorYear/,/\}$/p". Зверніть увагу на $символ. Це добре працює, за винятком того, що він не друкує закриття }бібіту. Btw, чи sedпотрібне використання ?
Барун

@Barun використання sedзовсім не потрібно, я просто думав, що це буде найпростіший варіант. Я з’ясував трохи інший код: sed -n "/AuthorYear/, /^ *\}/p"який, здається, робить саме те, що я хочу, включаючи закриття }та виправлення пробілів, якщо такі є
Міхель

Відповіді:


2

Наступний сценарій Python виконує потрібну фільтрацію.

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

Особисто я віддаю перевагу переходу до мови сценаріїв, коли логіка фільтрування стає складною. Це, мабуть, має перевагу принаймні щодо коефіцієнта читабельності.


Обережно, є багато записів із вкладеними {}s. Якщо ви можете переконатися, що запис закінчується \n}, ви можете зупинитись на^}
vonbrand

8

Я рекомендую використовувати мову з протестованою бібліотекою бібліотекою BibTeX, а не винаходити це колесо. Наприклад

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

Можливо, вам доведеться встановити модуль: cpan install BibTeX::Parser


1

Тепер у нас також є модуль бібпарсингу Python, який дозволяє аналізувати бази даних BibTeX з Python. Наприклад, я використовую наступний сценарій для обчислення кількості авторів у спільних роботах:

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

Іншим варіантом буде використання bibtool.

Приклад:

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

Перегляньте посібник для конкретних випадків.


0

Це сценарій Bash, який читає кожен рядок і використовує відповідність регулярного вираження для вилучення кожного запису, який має в голові потрібний візерунок. Ви можете назвати це getbibsчи щось:

#!/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 року, ви можете зробити:

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

Можливо, є деякі проблеми, які я ще не перевіряв, але, здається, справляється із цим завданням.


0

Щоб бути повноцінним, те, як я зрозумів, не так приємно, як деякі інші, але це працює:

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

Його можна запустити з командного рядка або поставити в скрипт bash.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.