Заменить N-е вхождение символа в строке чем-то другим - PullRequest
3 голосов
/ 27 апреля 2019

Рассмотрим a = paste(1:10,collapse=", "), что приводит к

a = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10"

Я хотел бы заменить каждое n-ое (скажем, 4-е) вхождение "," и заменить его чем-то другим (скажем "\ n«).Желаемый результат будет:

"1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"

Я ищу код, который использует gsub (или что-то эквивалентное) и некоторую форму regular expression для достижения этой цели.

Ответы [ 4 ]

7 голосов
/ 27 апреля 2019

Вы можете заменить ((?:\d+, ){3}\d), на \1\n

Вы в основном записываете все до четвертой запятой в группе 1 и запятой отдельно и заменяете ее на \1\n, которая заменяет сопоставленный текст текстом группы 1 и новой строкой, давая вам ожидаемые результаты.

Regex Demo

Демоверсия кода R

gsub("((?:\\d+, ){3}\\d),", "\\1\n", "1, 2, 3, 4, 5, 6, 7, 8, 9, 10")

печать

[1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"

Edit:

Чтобы обобщить приведенное выше решение для любого текста, мы можем изменить \d на [^,]

Новая демонстрация кода R

gsub("((?:[^,]+, ){3}[^,]+),", "\\1\n", "1, 2, 3, 4, 5, 6, 7, 8, 9, 10")
gsub("((?:[^,]+, ){3}[^,]+),", "\\1\n", "a, bb, ccc, dddd, 500, 600, 700, 800, 900, 1000")

Выход

[1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"
[1] "a, bb, ccc, dddd\n 500, 600, 700, 800\n 900, 1000"
1 голос
/ 27 апреля 2019

regmatches как еще одна альтернатива:

a <- "1, 2, 3, 4, 5, 6, 7, 8, 9, 10"

fn <- ","
rp <- "\n"
n <- 4

regmatches(a, gregexpr(fn, a)) <- list(c(rep(fn,n-1),rp))
a
#[1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"

Как функция:

a <- "1, 2, 3, 4, 5, 6, 7, 8, 9, 10"

replN <- function(x, fn, rp, n) {
    regmatches(x, gregexpr(fn, x)) <- list(c(rep(fn,n-1),rp))
    x
}
replN(a, ",", "\n", 4)
#[1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10

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

a = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10"

replN <- function(x,fn,rp,n) {
    sel <- rep(fn, n*length(rp))
    sel[seq_along(rp)*n] <- rp
    regmatches(x, gregexpr(fn, x)) <- list(sel)
    x
}
replN(a, fn=",", rp=c("1st","2nd"), n=4)
#[1] "1, 2, 3, 41st 5, 6, 7, 82nd 9, 10"
1 голос
/ 27 апреля 2019

регулярное выражение - лучшая альтернатива, тем не менее, вот другой подход без регулярного выражения

> str_vec <- strsplit(a, " ")[[1]] 
> where <- seq_along(str_vec) %% 4 == 0
> str_vec[where] <- sub(",", "\n", str_vec[where])
> paste(str_vec, collapse=" ")
[1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"
1 голос
/ 27 апреля 2019

Использование regex и gsub.

a = paste(1:10,collapse=", ")
x <- gsub("([^,]*,[^,]*,[^,]*,[^,]*),", '\\1\n', a)
x
#> [1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...