регулярное выражение заменить части / группы строки в R - PullRequest
3 голосов
/ 24 октября 2019

Попытка постобработки LaTeX (вывод pdf_book) документа уценки, чтобы свернуть цитаты из biblatex, чтобы иметь возможность сортировать их в хронологическом порядке, используя \usepackage[sortcites]{biblatex} позже. Таким образом, мне нужно найти }{ после \\autocites и заменить его на ,. Я экспериментирую с gsub(), но не могу найти правильное заклинание.

# example input
testcase <- "text \\autocites[cf.~][]{foxMapping2000}{wattPattern1947}{runkleGap1990} text {keep}{separate}"

# desired output
"text \\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990} text {keep}{separate}"

Простой подход состоял в том, чтобы заменить все }{

> gsub('\\}\\{', ',', testcase, perl=TRUE)
[1] "text \\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990} text {keep,separate}"

Но это также разрушает {keep}{separate}.

Затем я пытался заменить }{ в «слове» (строке символов без пробелов), начиная с \\autocites, используя разные группы и с горечью завершив:

> gsub('(\\\\autocites)([^ \f\n\r\t\v}{}]+)((\\}\\{})+)', '\\1\\2\\3', testcase, perl=TRUE)
[1] "text \\autocites[cf.~][]{foxMapping2000}{wattPattern1947}{runkleGap1990} some text {keep}{separate}"

Приложение : Фактический документ содержит больше строк / элементов, чем приведенный выше тестовый пример. Не все элементы содержат \\autocites, а в редких случаях один элемент имеет более одного \\autocites. Изначально я не думал, что это актуально. Более реалистичный тестовый пример:

testcase2 <- c("some text",
"text \\autocites[cf.~][]{foxMapping2000}{wattPattern1947}{runkleGap1990} text {keep}{separate}",
"text \\autocites[cf.~][]{foxMapping2000}{wattPattern1947}{runkleGap1990} text {keep}{separate} \\autocites[cf.~][]{foxMapping2000}{wattPattern1947}")

Ответы [ 4 ]

3 голосов
/ 24 октября 2019

Достаточно одного gsub вызова:

gsub("(?:\\G(?!^)|\\\\autocites)\\S*?\\K}{", ",", testcase, perl=TRUE)
## => [1] "text \\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990} text {keep}{separate}"

См. Демонстрационную версию regex . Здесь (?:\G(?!^)|\\autocites) соответствует концу предыдущего совпадения или строке \autocites, затем оно соответствует любым 0 или более непробельным символам, но как можно меньше, тогда \K отбрасывает текст из буфера текущего совпадения и используетподстрока }{, которая в конечном итоге заменяется запятой.

Существует также очень удобочитаемое решение с одним регулярным выражением и одной фиксированной заменой текста с использованием stringr::str_replace_all:

library(stringr)
str_replace_all(testcase, "\\\\autocites\\S+", function(x) gsub("}{", ",", x, fixed=TRUE))
# => [1] "text \\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990} text {keep}{separate}"

Здесь\\autocites\S+ соответствует \autocites, а затем 1+ непробельных символов, а gsub("}{", ",", x, fixed=TRUE) заменяет (очень быстро) каждый }{ на , в сопоставленном тексте.

1 голос
/ 24 октября 2019

Не самое красивое решение, но оно работает. Это многократно заменяет} {на, но только если оно следует за автогородами без промежуточных пробелов.

while(length(grep('(autocites\\S*)\\}\\{', testcase, perl=TRUE))) {
    testcase = sub('(autocites\\S*)\\}\\{', '\\1,', testcase, perl=TRUE)
}

testcase
[1] "text \\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990} text {keep}{separate}"
0 голосов
/ 24 октября 2019

Я нашел заклинание, которое работает. Это не красиво:

gsub("\\\\autocites[^ ]*",
  gsub("\\}\\{",",",
    gsub(".*(\\\\autocites[^ ]*).*","\\\\\\1",testcase) #all those extra backslashes are there because R is ridiculous.
    ),
  testcase)

Я разбил его на строки, чтобы, надеюсь, сделать его немного понятнее. По сути, самый внутренний gsub извлекает только автоциты (все, что следует за \\autocites до первого пробела), затем середина gsub заменяет }{ с запятыми, а крайняя gsub заменяет результатсредний для шаблона, извлеченного из самого внутреннего.

Конечно, это будет работать только с одиночными автоцитами в строке.

Также, fortune(365).

0 голосов
/ 24 октября 2019

Я сделаю входную строку немного больше, чтобы сделать алгоритм более понятным.

str <- "
text \\autocites[cf.~][]{foxMapping2000}{wattPattern1947}{runkleGap1990} text {keep}{separate}
text \\autocites[cf.~][]{wattPattern1947}{foxMapping2000}{runkleGap1990} text {keep}{separate}
"

Сначала мы извлечем все блоки цитирования, заменим "}{" на "," в них, а затем поместимвернуть их обратно в строку.

# pattern for matching citation blocks
pattern <- "\\\\autocites(\\[[^\\[\\]]*\\])*(\\{[[:alnum:]]*\\})+"
cit <- str_extract_all(str, pattern)[[1]]
cit

#> [1] "\\autocites[cf.~][]{foxMapping2000}{wattPattern1947}{runkleGap1990}"
#> [2] "\\autocites[cf.~][]{wattPattern1947}{foxMapping2000}{runkleGap1990}"

Заменить в блоках цитирования:

newcit <- str_replace_all(cit, "\\}\\{", ",")
newcit
#> [1] "\\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990}"
#> [2] "\\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990}"

Разбить исходную строку в местах, где был найден блок цитирования

strspl <- str_split(str, pattern)[[1]]
strspl
#> [1] "\ntext "  " text {keep}{separate}\ntext "  " text {keep}{separate}\n"

Вставьте измененные блоки цитирования:

combined <- character(length(strspl) + length(newcit))
combined[c(TRUE, FALSE)] <- strspl
combined[c(FALSE, TRUE)] <- newcit
combined
#> [1] "\ntext "                                                          
#> [2] "\\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990}"
#> [3] " text {keep}{separate}\ntext "                                    
#> [4] "\\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990}"
#> [5] " text {keep}{separate}\n"

Вставьте его вместе, чтобы завершить:

newstr <- paste(combined, collapse = "")
newstr
#> [1] "\ntext \\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990} text {keep}{separate}\ntext \\autocites[cf.~][]{foxMapping2000,wattPattern1947,runkleGap1990} text {keep}{separate}\n"

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...