Как заменить определенные c завершающие символы, но заблокировать первые две буквы - PullRequest
2 голосов
/ 11 июля 2020

Я хочу согласовать строки, заменив все завершающие X и Y символами подчеркивания. Поскольку длина этих строк варьируется, я написал следующее регулярное выражение, которое отлично работает. Однако первые два символа всегда должны оставаться такими, какие они есть. Я знаю, что могу использовать substr() и paste0() в качестве обходного пути, но как я могу включить это «не заменять первые два символа» в регулярное выражение?

x <- c("AXZ", "AZXYYX", "HZX_Y", "BXX", "XYX_")

# replaces all trailing X / Y
gsub("[XY](?=[XY_]*$)", "_", x, perl = TRUE)
#> [1] "AXZ"    "AZ____" "HZ___"  "B__"    "____"

# blocks first character
gsub("(?<!^)[XY](?=[XY_]*$)", "_", x, perl = TRUE)
#> [1] "AXZ"    "AZ____" "HZ___"  "B__"    "X___"

# desired output
c("AXZ", "AZ____", "HZ___", "BX_", "XY__")
#> [1] "AXZ"    "AZ____" "HZ___"  "BX_"    "XY__"

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

Ответы [ 3 ]

4 голосов
/ 11 июля 2020

Кажется, работает следующий подход:

gsub("(?<=.{2})[XY](?=[XY_]*$)", "_", x, perl=TRUE)

[1] "AXZ"    "AZ____" "HZ___"  "BX_"    "XY__"

Вот объяснение шаблона регулярного выражения, который использует поисковые запросы для обеспечения правильной замены:

(?<=.{2})        lookbehind and assert there exist at least 2 preceding characters;
                 this ensures replacement will never be made on first 2 characters
[XY]             match any of X or Y
(?=[XY_]*$)      lookahead and assert that previous X/Y/_ is only followed
                 by more X/Y/_ until the end of the string

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

3 голосов
/ 11 июля 2020

Вы можете просто пропустить первые два символа, используя (*SKIP)(*FAIL):

x <- c("AXZ", "AZXYYX", "HZX_Y", "BXX", "XYX_")

gsub("^.{2}(*SKIP)(*FAIL)|[XY](?=[XY_]*$)", "_", x, perl = TRUE)

, что дает

[1] "AXZ"    "AZ____" "HZ___"  "BX_"    "XY__"  

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

0 голосов
/ 11 июля 2020

Один из способов сделать это - захватить два предыдущих символа и повторить их. Вы можете использовать '\ 1', '\ 2' и c. в строке подстановки для ссылки на 1-й, 2-й и т. д. c. группы захвата соответственно. Здесь у нас только одна группа захвата.

sub("(..)[XY]+$)", "\\1_", x, perl = TRUE)
...