Как сделать замену обратными ссылками, когда количество вхождений неизвестно? - PullRequest
0 голосов
/ 07 мая 2018

Чтобы внести несколько исправлений в файл .tex, сгенерированный Bookdown, мне нужно заменить вхождения }{ на ,, когда он используется в цитате, т.е.

s <- "Text.\\autocites{REF1}{REF2}{REF3}. More text \\autocites{REF4}{REF5} and \\begin{tabular}{ll}"

Должен стать

"Text.\\autocites{REF1,REF2,REF3}. More text \\autocites{REF4,REF5} and \\begin{tabular}{ll}

Поскольку мне нужно сохранить ссылки, я пытался просмотреть обратные ссылки, но я не могу понять, как это правильно, потому что количество групп, которые нужно сопоставить, заранее неизвестно. Кроме того, я не могу сделать stringr::str_replace_all(s, "\\}\\{", ","), потому что }{ встречается и в других местах документа.

Мой лучший подход на данный момент - использовать функцию «смотреть в прошлое», чтобы выполнять замену только в том случае, если вхождение происходит после \\autocites, но тогда я не могу получить обратные ссылки и правильную группировку:

stringr::str_replace_all(s, "(?<=\\\\autocites\\{)([:alnum:]+)(\\}\\{)", "\\1,")
[1] "Text.\\autocites{REF1,REF2}{REF3}. More text \\autocites{REF4,REF5} and \\begin{tabular}{ll}"

stringr::str_replace_all(s, "(?<=\\\\autocites\\{)([:alnum:]+)((\\}\\{)([:alnum:]+))*", "\\1,\\4")
[1] "Text.\\autocites{REF1,REF3}. More text \\autocites{REF4,REF5} and \\begin{tabular}{ll}"

Возможно, мне не хватает какого-то совершенно очевидного подхода, поэтому я надеюсь, что кто-то может помочь.

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

pat совпадений

  • autocites с последующим
  • самая короткая строка, которая заканчивается } и
  • с последующим концом строки или не- {

Затем он использует gsubfn для замены каждого вхождения }{ в этом запятой. Он использует формульную нотацию для выражения функции замены - тело функции находится в правой части ~, а поскольку тело содержит ..1, аргументы принимаются равными .... Он не использует взгляды нулевой ширины или взгляд назад.

library(gsubfn)

pat <- "(autocites.*?\\}($|[^{]))"
gsubfn(pat, ~ gsub("}{", ",", ..1, fixed = TRUE), s)

дает:

[1] "Text.\\autocites{REF1,REF2,REF3}. More text \\autocites{REF4,REF5} and \\begin{tabular}{ll}"

Изменение

Одно небольшое упрощение регулярного выражения, показанного выше, состоит в том, чтобы удалить внешние скобки из pat и вместо этого указать backref = 0 в gsubfn. Это говорит о том, чтобы передать все совпадение в функцию. Мы могли бы использовать ..1 для указания аргумента, как указано выше, но, поскольку мы знаем, что обязательно передан только один аргумент, мы можем указать его как x в теле функции. Любое имя переменной будет делать, поскольку предполагается, что любая свободная переменная является аргументом. Вывод будет таким же, как указано выше.

pat2 <- "autocites.*?\\}($|[^{])"
gsubfn(pat2, ~ gsub("}{", ",", x, fixed = TRUE), s, backref = 0)
0 голосов
/ 07 мая 2018

Крутая проблема - я должен выучить новый трюк с str_replace. Вы можете сделать возвращаемое значение функцией, и она применяет функцию к выбранным вами строкам.

replace_brakets <- function(str) {
  str_replace_all(str, "\\}\\{", ",")
}

s %>% str_replace_all("(?<=\\\\autocites\\{)([:alnum:]+\\}\\{)+", replace_brakets)
# [1] "Text.\\autocites{REF1,REF2,REF3}. More text \\autocites{REF4,REF5} and \\begin{tabular}{ll}"
...