7
votes

Remplacez la Nième occurrence d'un caractère dans une chaîne par autre chose

Considérez a = paste (1: 10, collapse = ",") qui se traduit par

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

Je voudrais remplacer tous les n-ièmes (par exemple 4-ème) occurrences de "," et remplacez-le par autre chose (dites "\ n"). La sortie souhaitée serait:

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

Je recherche un code qui utilise gsub (ou quelque chose d'équivalent) et une forme de régulier expression pour atteindre cet objectif.


2 commentaires

Essayez-vous d'apprendre gsub ou regex?


L'expression régulière est simple, ((?: \ D +,) {3}) (\ d +), réécrire $ 1 $ 2 \\ n


4 Réponses :


11
votes

Vous pouvez remplacer ((?: \ d +,) {3} \ d), par \1\n

En gros, vous capturez tout jusqu'à la quatrième virgule dans group1 et virgule séparément et remplacez-le par \ 1 \ n qui remplace le texte correspondant par le texte du groupe1 et une nouvelle ligne, vous donnant les résultats escomptés.

Démo Regex

Démo R Code

[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"

Prints,

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")


3 commentaires

Pouvons-nous remplacer \ d par autre chose pour le rendre plus général? Disons qu'au lieu de chiffres uniques, nous pouvons avoir une chaîne aléatoire telle que "a, bb, ccc, dddd, 500, 600, 700, 800, 900, 1000" et nous voulons remplacer tous les 4 -ème virgule avec '\ n'.


Bien sûr, nous pouvons remplacer \ d par [^,] +


@Mahmoud: J'ai mis à jour ma réponse pour la rendre générale et pas seulement pour les chiffres.



1
votes

En utilisant à la fois regex et 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"


0 commentaires

1
votes

regex est la meilleure alternative, mais voici une autre approche sans regex

> 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"


0 commentaires

1
votes

regmatches comme une autre alternative:

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"

En tant que fonction:

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

Vous pouvez même étendre ceci à vectoriser sur l'argument de remplacement:

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"


0 commentaires