Как заменить квадратные скобки фигурными скобками с помощью регулярного выражения R?

Из-за преобразований между pandoc-citeproc и латексом я хотел бы заменить это

[@Fotheringham1981]

с этим

\cite{Fotheringham1981} .

Проблема обработки каждой скобки отдельно показана в воспроизводимом примере ниже.

x <- c("[@Fotheringham1981]", "df[1,2]")
x1 <- gsub("\\[@", "\\\\cite{", x)
x2 <- gsub("\\]", "\\}", x1)

x2[1] # good
## [1] "\\cite{Fotheringham1981}"

x2[2] # bad
## [1] "df[1,2}"

Видел похожую проблему решенную для С#, но не используя регулярное выражение R perly - есть идеи?

Редактировать:

Он должен быть в состоянии обрабатывать длинные документы, например.

old_rmd <- "$p = \alpha e^{\beta d}$ [@Wilson1971] and $p = \alpha d^{\beta}$
[@Fotheringham1981]."
new_rmd1 <- gsub("\\[@([^\\]]*)\\]", "\\\\cite{\\1}", old_rmd, perl = T) 
new_rmd2 <- gsub("\\[@([^]]*)]", "\\\\cite{\\1}", old_rmd) 

new_rmd1
## "$p = \alpha e^{\beta d}$ \\cite{Wilson1971} and $p = \alpha d^{\beta}$\n    \\cite{Fotheringham1981}."

new_rmd2
## [1] "$p = \alpha e^{\beta d}$ \\cite{Wilson1971} and $p = \alpha d^{\beta}$\n\\cite{Fotheringham1981}."

person RobinLovelace    schedule 09.11.2015    source источник
comment
Бонусные баллы за регулярное выражение, которое может сделать обратное!   -  person RobinLovelace    schedule 09.11.2015


Ответы (3)


Ты можешь использовать

gsub("\\[@([^]]*)]", "\\\\cite{\\1}", x)

См. демонстрацию IDEONE.

Разбивка регулярных выражений:

  • \\[@ - буквальная последовательность символов [@
  • ([^]]*) — группа захвата 1, которая соответствует 0 или более вхождениям любого символа, кроме ] (обратите внимание, что если ] появляется в начале класса символов, его не нужно экранировать)
  • ] - буквальный символ ]

Вам не нужно использовать perl=T с этим, потому что ] внутри класса символов не экранируется. В противном случае потребуется использовать эту опцию.

Кроме того, я считаю, что мы должны избегать только того, от чего следует избегать. Если есть способ избежать ад обратной косой черты, мы должны это сделать. Таким образом, вы даже можете использовать

gsub("[[]@([^]]*)]", "\\\\cite{\\1}", x)

Вот еще одна демонстрация

Почему регулярное выражение на основе TRE работает лучше, чем на PCRE:

В R 2.10.0 и более поздних версиях механизм регулярных выражений по умолчанию представляет собой модифицированную версию механизма TRE Вилле Лаурикари [source ]. автор библиотеки утверждает, что время, затрачиваемое на сопоставление, растет линейно с увеличением длины входного текста, при этом требования к памяти почти постоянны (десятки килобайт). TRE также утверждается, что использует предсказуемое и умеренное потребление памяти и квадратичное время наихудшего случая в длине используемый алгоритм сопоставления регулярных выражений. Вот почему при работе с большими документами лучше полагаться на TRE, а не на регулярное выражение PCRE.

person Wiktor Stribiżew    schedule 09.11.2015
comment
То есть вы имеете в виду, что [[] лучше, чем \\[? - person Avinash Raj; 09.11.2015
comment
:) Нет, это то же самое. В выражении POSIX экранирование невозможно внутри класса символов, но возможно снаружи. Я только что показал синонимическое выражение, в котором не происходит экранирования. - person Wiktor Stribiżew; 09.11.2015

Вам нужно использовать группу захвата.

x <- c("[@Fotheringham1981]", "df[1,2]")
gsub("\\[@([^\\]]*)\\]", "\\\\cite{\\1}", x, perl=T)
# [1] "\\cite{Fotheringham1981}" "df[1,2]" 

or

gsub("\\[@(.*?)\\]", "\\\\cite{\\1}", x)
# [1] "\\cite{Fotheringham1981}" "df[1,2]"
person Avinash Raj    schedule 09.11.2015
comment
да, некоторые люди могут спутать с вашим. - person Avinash Raj; 09.11.2015
comment
Я просто хочу подчеркнуть, что мы должны бежать только от того, от чего нужно бежать. Если есть способ избежать ад обратной косой черты, мы должны это сделать. - person Wiktor Stribiżew; 09.11.2015
comment
@stribizhev ваш ответ более лаконичен и работает для преобразования моего длинного файла .Rmd - вы должны получить «правильный» ответ IMO! Спасибо также за ваш ответ, Ав, но, похоже, он не работает для длинных документов. - person RobinLovelace; 09.11.2015
comment
@RobinLovelace Что ты имеешь в виду? Он просто избегает побега. Я не знаю, как регулярное выражение от него работает со строкой, где моя не сработает. Вы также можете рассмотреть это gsub("\\[@([^][]*)]", "\\\\cite{\\1}", x). - person Avinash Raj; 09.11.2015
comment
@RobinLovelace, да, вам нужно добавить perl=T. - person Avinash Raj; 09.11.2015
comment
@AvinashRaj ОК, извиняюсь - person RobinLovelace; 09.11.2015

Это соответствует [@, а затем устанавливает группу захвата, то есть все в пределах (...), а затем .*? соответствует самой короткой строке до ] :

gsub("\\[(@.*?)\\]", "\\\\cite{\\1}", x)
## [1] "\\cite{@Fotheringham1981}" "df[1,2]" 

Вот железнодорожная диаграмма регулярного выражения:

\[(@.*?)\]

Визуализация регулярных выражений

Демонстрация отладки

person G. Grothendieck    schedule 09.11.2015