1
votes

Regex pour supprimer les doublons non adjacents dans R

J'ai du mal à trouver une expression régulière qui supprime les caractères dupliqués dans une chaîne (c'est-à-dire ne garde que la première occurrence)

En particulier, je veux supprimer tous les deux-points après la première apparition

str_remove(string = s, pattern = "(:)(?=.*\1)")
# [1] "note: conducted by j:m"  "location: made :n :apan" "date: 2010, ma: 3rd" 


0 commentaires

4 Réponses :


2
votes

Essayez d'utiliser sub en deux étapes ici:

s <- c("note: conducted by j:m",
       "location: made in :apan",
       "date: 2010, ma: 3rd")

Données:

first <- sub("^(.*?:).*", "\\1", s)
second <- sub("^.*?:", "", s)
second <- sub(":", "", second, fixed=TRUE)
out <- paste0(first, second)
out

[1] "note: conducted by jm"  "location: made in apan" "date: 2010, ma 3rd"

L'approche ici consiste à capturer chaque chaîne jusqu'au premier deux-points inclus dans une variable, puis à capturer le reste de chaque chaîne dans une deuxième variable. Ensuite, nous supprimons les deux-points uniquement de la deuxième variable, et enfin nous collons les deux éléments ensemble pour générer la sortie attendue.

Notez qu'une manière plus concise de le faire serait d'utiliser sub ou peut-être str_replace_all avec une fonction de rappel, mais la syntaxe n'est pas si simple.


2 commentaires

à la recherche d'une façon plus concise de faire cela, c'est-à-dire une regex simple ... sur certaines lignes j'ai plus de deux : et je cours sur des dizaines de milliers de lignes, donc en créant des objets intermédiaires je suis inquiet de la vitesse - peut-être inutilement?


Comme je l'ai mentionné dans ma réponse, vous pourriez trouver un moyen de remplacer l'expression régulière en utilisant une ligne unique avec une fonction de rappel. Mais , même cela ne serait pas nécessairement plus efficace que la solution dans ma réponse.



0
votes

Vu le problème posé, les expressions régulières semblent être un moyen trop compliqué de faire cela. Un moyen non-regex n'est-il pas beaucoup plus simple? Comme celui-ci:

for s in ss:
    it = re.subn( ":", "#", s, count=1 ) #Replace the first ":" with "#" to distinguish it from others
    print( it[0].replace( ":", "" ).replace( "#", ":" ) ) #Remove remaining ":"s and bring back the original

Bien sûr, si vous préférez une solution basée sur les regex pour une autre raison, cela ne fonctionnera pas. (De plus, la solution donnée est en Python et non en R, vous l'avez peut-être remarqué.)


1 commentaires

@TimBiegeleisen Bon point. Si la nature des données d'entrée est connue, nous pouvons choisir un ou plusieurs caractères en conséquence. Par exemple, si je sais que # $ # $ ^ & ^ # $ ne viendra jamais dans la chaîne d'entrée, je peux choisir cela au lieu de # .



1
votes

Malheureusement, " Les correspondances de modèle Look-Behind doivent avoir une longueur maximale limitée. "

Donc, L'approche de Tim est probablement la voie à suivre

  1. diviser chaque chaîne en deux parties,
  2. supprimer tout : de la deuxième partie, et
  3. reconcaténer la première partie et la seconde partie modifiée

Voici une implémentation en une seule ligne:

s <- c("note: conducted by j:m",
       "location: made :n :apan",
       "date: 2010, ma: 3rd",
       "no double colon",
       "test1::::",
       "test2: colon1: colon2: end")

qui renvoie

[1] "note: conducted by jm"    "location: made n apan"    "date: 2010, ma 3rd"      
[4] "no double colon"          "test1:"                   "test2: colon1 colon2 end"

pour un exemple de vecteur de caractères amélioré (y compris quelques cas de contour):

library(stringr)
sapply(str_split(s, "(?<=:)", n = 2L), function(x) paste0(x[1L], str_remove_all(x[-1L], ":")))


0 commentaires

2
votes

Essayez ce modèle:

str = "location: made : in japan: or what:"
str.gsub(/(?:^[^:]*:|\G(?!^))[^:]*\K:/, '')

Maintenant, ce que je ne sais pas, si cela serait applicable à Ruby car je ne sais presque rien à ce sujet pour être honnête.

J'ai eu cet exemple pour travailler sur une seule chaîne me laissant penser qu'il devrait fonctionner =)

(?:^[^:]*:|\G(?!^))[^:]*\K:


1 commentaires

parfait ... fonctionne avec gsub (x = s, pattern = "(?: ^ [^:] *: | \\ G (?! ^)) [^:] * \\ K:", remplacement = "", perl = TRUE)