Вопрос или проблема
Мне дали длинный документ Word, который я должен перенести в Latex. В документе все цитаты представлены в классической форме с автором и годом. Что-то вроде
Lorem ipsum dolor (Sit, 1998) amet, consectetur adipiscing (Slit 2000, Sed and So 2002, Eiusmod et al. 1976).
Tempor incididunt ut labore et dolore magna aliqua (Ut et al. 1312)
Эти ссылки должны получить правильный ключ ссылки, как это указано в списке bibliograph. Другими словами, текст должен переводиться в
Lorem ipsum dolor \cite{sit1998} amet, consectetur adipiscing \cite{slit2000,sed2002,eiusmod1976}.
Tempor incididunt ut labore et dolore magna aliqua \cite{ut1312}
Это означает:
- извлечь все строки, состоящие из имени(имён) и года, заключённых в скобки
- убрать из этой строки пробелы, вторые имена (всё после первого имени) и прописные буквы
- использовать получившуюся строку для формирования нового \cite{строка}
Я понимаю, что это может быть довольно сложной задачей. Мне интересно, возможно, кто-то написал скрипт для этой конкретной задачи. В качестве альтернативы, любые частичные предложения также приветствуются. В настоящее время я работаю в MacOS.
Следующая awk
программа должна работать. Она ищет элементы ( ... )
в каждой строке и проверяет, соответствуют ли они шаблону “автор(ы), год” или “автор(ы)1 год1, автор(ы)2 год2, …”. Если да, то она создает команду ссылки и заменяет группу ( ... )
; в противном случае она оставляет группу такой, какая она есть.
#!/usr/bin/awk -f
# Эта небольшая функция создает строку в стиле 'authorYYYY' из
# отдельных полей автора и года. Мы дополнительно разбиваем поле "автор"
# по каждому пробелу, чтобы убрать начальные/конечные
# пробелы и других авторов.
function contract(author, year)
{
split(author,auth_fields," ");
auth=tolower(auth_fields[1]);
return sprintf("%s%4d",auth,year);
}
# Эта функция проверяет, соответствуют ли две строки "имени(имён) автора" и
# "году" соответственно.
function check_entry(string1, string2)
{
if (string1 ~ /^ *([[:alpha:].-]+ *)+$/ && string2 ~ /^ *[[:digit:]]{4} *$/) return 1;
return 0;
}
# Эта функция создает команду 'citation' из сырого элемента. Если сырой
# элемент не соответствует синтаксису ссылки 'автор, год' или
# 'автор1 год1,автор2 год2, ...', мы должны оставить его "таким, какой он есть",
# и вернуть "0" в качестве индикатора.
function create_cite(raw_elem)
{
cite_argument=""
# Делим по ','. Отдельные элементы - это либо имя(список) и год,
# либо варианты имя(список)-год, разделённые пробелами.
n_fields=split(raw_elem,sgl_elem,",");
if (n_fields == 2 && check_entry(sgl_elem[1],sgl_elem[2]))
{
cite_argument=contract(sgl_elem[1],sgl_elem[2]);
}
else
{
for (k=1; k<=n_fields; k++)
{
n_subfield=split(sgl_elem[k],subfield," ");
if (check_entry(subfield[1],subfield[n_subfield]))
{
new_elem=contract(subfield[1],subfield[n_subfield]);
if (cite_argument == "")
{
cite_argument=new_elem;
}
else
{
cite_argument=sprintf("%s,%s",cite_argument,new_elem);
}
}
else
{
return 0;
}
}
}
cite=sprintf("\\{%s}",cite_argument);
return cite;
}
# Основная программа
# Для каждой строки создаем "рабочую копию", чтобы мы могли заменить
# уже обработанные пары '(...)' другим текстом (здесь: 'X ... Y');
# в противном случае 'sub' всегда будет натыкаться на одну и ту же
# открытую скобку.
# Для каждой найденной '( ... )' проверяем, соответствует ли она шаблону.
# Если да, мы заменяем её на команду 'cite'; в противном случае мы оставляем её такой, какая она есть.
{
working_copy=$0;
# Разрешаем несовпадающие ')' в начале строки:
# если ')' была найдена до первой '(', помечаем это как обработанное
i=index(working_copy,"(");
j=index(working_copy,")");
if (i>0 && j>0 && j
Вызовите программу с помощью
~$ awk -f transform_citation.awk input.tex
Примечание, что программа ожидает, что ввод будет "разумно" хорошо сформирован, т.е. все скобки в строке должны быть парными (хотя допускается одна закрывающая скобка в начале строки, и несоответствующие открытые скобки будут проигнорированы).
Отметьте также, что некоторый синтаксис выше требует GNU awk. Чтобы быть переносимым для других реализаций, замените
if (string1 ~ /^ *([[:alpha:].-]+ *)+$/ && string2 ~ /^ *[[:digit:]]{4} *$/) return 1;
на
if (string1 ~ /^ *([a-zA-Z.-]+ *)+$/ && string2 ~ /^ *[0123456789][0123456789][0123456789][0123456789] *$/) return 1;
и убедитесь, что вы установили локаль сортировки на C
.
Ответ или решение
Для преобразования библиографических ссылок из текстового формата в формат, совместимый с LaTeX, необходима программа, способная извлечь, обработать и преобразовать ссылки, оформленные в виде "(Автор, Год)" в соответствующие команды \cite{ключ}. Эта задача может быть выполнена с помощью скрипта на awk, который эффективно находит текст внутри круглых скобок, проверяет его на соответствие требуемому формату и заменяет его на требуемые команды.
Общие шаги преобразования:
- Извлечение строк: На первом этапе программа анализирует текст и выделяет все строки, заключенные в круглые скобки.
- Обработка строк: После извлечения строк следует их обработка: необходимо удалить лишние пробелы, второстепенные имена авторов и привести названия к нижнему регистру.
- Формирование команд \cite{}: На основе обработанных строк формируются команды для цитирований в LaTeX формате.
Пример реализации на awk:
Следующий скрипт awk выполняет перечисленные требования:
#!/usr/bin/awk -f
# Функция для создания строки 'authorYYYY' из имени и года
function contract(author, year) {
split(author,auth_fields," ");
auth=tolower(auth_fields[1]);
return sprintf("%s%4d",auth,year);
}
# Функция для проверки соответствия строк формату "Автор(ы) Год"
function check_entry(string1, string2) {
if (string1 ~ /^ *([[:alpha:].-]+ *)+$/ && string2 ~ /^ *[[:digit:]]{4} *$/) return 1;
return 0;
}
# Функция для создания команды ссылки из оригинального элемента
function create_cite(raw_elem) {
cite_argument="";
n_fields=split(raw_elem, sgl_elem, ",");
if (n_fields == 2 && check_entry(sgl_elem[1], sgl_elem[2])) {
cite_argument=contract(sgl_elem[1], sgl_elem[2]);
} else {
for (k=1; k<=n_fields; k++) {
n_subfield=split(sgl_elem[k], subfield, " ");
if (check_entry(subfield[1], subfield[n_subfield])) {
new_elem=contract(subfield[1], subfield[n_subfield]);
if (cite_argument == "") {
cite_argument=new_elem;
} else {
cite_argument=sprintf("%s,%s", cite_argument, new_elem);
}
} else {
return 0;
}
}
}
cite=sprintf("\\cite{%s}", cite_argument);
return cite;
}
# Основная программа
{
working_copy=$0;
i=index(working_copy,"(");
j=index(working_copy,")");
if (i > 0 && j > 0 && j < i) sub(/\)/,"Y",working_copy);
while (i=index(working_copy,"(")) {
sub(/\(/,"X",working_copy);
j=index(working_copy,")");
if (!j) {
continue;
}
sub(/\)/,"Y",working_copy);
elem=substr(working_copy,i+1,j-i-1);
replacement=create_cite(elem);
if (replacement != "0") {
elem="\\(" elem "\\)";
sub(elem, replacement);
}
}
print $0;
}
Запуск программы
Сохраните код в файл, например, transform_citation.awk
, и выполните команду:
awk -f transform_citation.awk input.tex > output.tex
Замечания
- Ограничения: Программа предполагает, что входные данные достаточно хорошо оформлены, все скобки должны быть парными. Настройте обработку исключений в случае несовпадений.
- Совместимость: Скрипт написан с учетом особенностей GNU awk. Если необходимо создать более портативное решение, рекомендуется заменить регулярные выражения на более совместимые с различными версиями awk.
Эта программа значительно упростит ваш процесс перевода ссылки из Word в LaTeX, ускоряя подготовку документа и минимизируя вероятность ошибок.