Замените группу захвата повторением одного символа, сохранив при этом длину группы захвата.

Предположим, вы хотите заменить AXA на AAA, а также AXXXXXA на AAAAAAA.

В основном любое количество символов X между двумя A с соответствующим количеством A.

Используя gsub(), я попытался:

gsub(x = "AXA", pattern = "(A)(X+)(\\1)", replacement = "\\1\\1\\1")

что дает AAA. Однако это AAA независимо от того, сколько времени X+ продлится. Как я могу получить доступ к длине подгруппы 2 в выводе?

Возможный дубликат этого: Заменить повторяющийся символ другим повторяющимся символом

Но ИМХО достаточно разные для отдельного вопроса.


person Stefan_R    schedule 15.05.2015    source источник
comment
этот символ X означает любой символ или конкретно X ?   -  person Nader Hisham    schedule 15.05.2015
comment
X — пример заменяемого символа. Может быть любым символом, но он не меняется в файле.   -  person Stefan_R    schedule 15.05.2015
comment
Итак, X всегда один и тот же символ в файле?   -  person zx8754    schedule 15.05.2015
comment
и начало и конец строк должны быть буквально A или это также может быть любой символ?   -  person Nader Hisham    schedule 15.05.2015
comment
X или N или 0, не имеет значения, также A можно изменить на что угодно, но обратите внимание, что нам нужна подгруппа 1, чтобы определить начало и конец замены. Окончательный вывод должен иметь ту же длину, что и ввод.   -  person Stefan_R    schedule 15.05.2015


Ответы (1)


У вас есть фиксированный шаблон замены: вы фиксируете A в первой группе, поэтому \\1 относится к A. Таким образом, вы получаете 3 А. Вам нужен другой подход: замените все последовательные X до A и после A. Это возможно с регулярным выражением в стиле Perl:

input = "AXXXA"
gsub("(?:A|(?<!^)\\G)\\KX(?=X*A)", "A", input, perl=TRUE)

Вывод демонстрационного кода:

[1] "AAAAA"

\G вызывает последовательное совпадение, а \K помогает нам отсечь первоначально совпадающее A. Упреждающий просмотр (?=X*A) гарантирует, что у нас есть любое количество X до A.

ИЗМЕНИТЬ:

Этот подход работает и с более длинными строками (здесь мы заменяем каждый Xyz между 123 на A):

input = "123XyzXyzXyz123"
gsub("(?:123|(?<!^)\\G)\\KXyz(?=(?:Xyz)*123)", "A", input, perl=TRUE)

Выход: [1] "123AAA123"

ИЗМЕНИТЬ 2:

Чтобы заменить любые буквы между 2 As, мы можем использовать класс сокращенных символов \p{L} для соответствия любой букве до A:

gsub("(?:A|(?<!^)\\G)\\K\\p{L}(?=\\p{L}*A)", "A", input, perl=TRUE)
=> [1] "XSDFAAAAAA"
person Wiktor Stribiżew    schedule 15.05.2015
comment
@ zx8754: Как именно это не сработало? Не могли бы вы объяснить тесты? Не вижу проблемы здесь: gsub("(?:A|(?<!^)\\G)\\K\\p{L}(?=\\p{L}*A)", "A", input, perl=TRUE) =› [1] "XSDFAAAAAA" Паттерн вместо X может быть любой, подход такой работающий. - person Wiktor Stribiżew; 15.05.2015
comment
ОК, EDIT 2 версия работает. Я уже проголосовал, просто хотел попросить сделать решение более надежным, спасибо. - person zx8754; 15.05.2015
comment
Это хорошее решение. Я не все понимаю, но постараюсь научиться. Спасибо Стрибижев. - person Stefan_R; 19.05.2015