Comment puis-je supprimer les caractères en double et garder l'unique uniquement.
Par exemple, mon entrée est la suivante: la sortie attendue est la suivante: p> je suis tombé sur perl -pe's / 1 $ // $ g tandis que /(.). [^\/'< / code> qui est merveilleux mais il retire même l'occurrence unique du caractère en sortie. P> P>
11 Réponses :
Ceci peut être fait à l'aide de positif lookahead : La regex utilisée est: Ce sera pas em> strong> maintenir l'ordre du char en entrée car pour chaque caractère unique dans la chaîne d'entrée, nous conservent son pour garder l'ordre relatif intact que nous pouvons faire ce que la ligne Perl Une ligne pour ceci est la suivante: p> puisque nous faisons Je ne sais pas si c'est le meilleur one-liner pour le faire. Je souhaite la bienvenue aux autres pour éditer cette réponse s'ils ont une meilleure alternative. P> p> (.) (? =. *? \ 1) code> p>
. code>: correspondre à n'importe quel caractère. LI>
() code>: rappelez-vous le correspondant
Simple Char. Li>
(? = ...) code>: + ve lookahead li>
. *? code>: Pour faire correspondre n'importe quoi entre li>
\ 1 code>: le match mémorisé. li>
(.) (? =. *? \ 1) code>: correspondez et rappelez-vous
tout char
s /// code>: Perl mode de faire le
substitution. li>
g code>: faire la substitution
globalement ... ça ne s'arrête pas après
première substitution. li>
s / (.) (? =. *? \ 1) // g code>: Ce sera
Supprimer un char de la chaîne d'entrée
Seulement si ce caractère apparaît à nouveau plus tard
dans la chaîne. li>
ul>
Kennytm code> raconte dans l'un des commentaires: p>
imprimer code> manuellement après inversion, nous ne le faisons pas Utilisez le drapeau
-p code> mais utilisez le drapeau
-n code>. p>
@Gavin: cela peut être corrigé en inversant la chaîne initialement et inverser la chaîne après le remplacement.
Eh bien c'est incroyable !!!! Mais pouvez-vous m'expliquer des détails du bit comme ce que ====> s / (.) Et (? =. *? \ 1) // fait? Il est également possible d'avoir dans le même ordre que j'ai mis dans ma première requête, pour ex. Actuellement, je reçois Efahu au lieu d'Efuah qui est plus utile. Thnax a tonne :)
@KennyTM: Merci :) @manu: J'ai mis à jour mes ans avec une courte explication de ce qui se passe.
Cela fonctionne exactement. Merci encore pour la réponse aimable et expliquer clairement toutes les choses. Merci tous :)
Pour un fichier contenant les données que vous liste nommées foo.txt
Son message original n'a pas spécifié Perl comme une exigence (bien qu'il l'a marqué Perl), il n'a fait que souligné qu'il a trouvé un Perl One-Liner comme un moyen possible de le faire. Il n'a pas non plus dit que la commande importait, seulement unicité. En outre, l'utilisation d'un one-liner indique que la méthode n'a pas d'importance.
Cravate :: ixhash est un bon module pour stocker l'ordre de hachage (mais peut être lent, vous devrez faire référence si la vitesse est importante). Exemple avec des tests:
use Test::More 0.88; use Tie::IxHash; sub dedupe { my $str=shift; my $hash=Tie::IxHash->new(map { $_ => 1} split //,$str); return join('',$hash->Keys); } { my $str='EFUAHUU'; is(dedupe($str),'EFUAH'); } { my $str='EFUAHHUU'; is(dedupe($str),'EFUAH'); } { my $str='UJUJHHACDEFUCU'; is(dedupe($str),'UJHACDEF'); } done_testing();
perl -ne'my%s;print grep!$s{$_}++,split//'
Cela fonctionne également et plus court qu'auparavant. Je suis submergé par la réponse :) J'aimerais connaître son travail si possible.
Cela fonctionne de la même manière que la solution de Gianthare, mais beaucoup plus de perl idiomatique et plus rapidement.
Un gentil, je suis d'accord. Presque une doublure sauf pour le mon% s code>. Bien que je ne vois pas d'où vient le speedUp. Qu'il s'agisse d'une hache fraîche au lieu de réinitialiser? Ou Grep est-il plus efficace que la boucle explicite?
@giantHare: Il y a la différence appelant impression code> pour chaque caractère et appelant
impression code> avec le paramètre Array. Votre code sera plus lent pour les lignes avec une plus grande quantité de caractères uniques.
% vu = (); code> devrait être presque aussi rapide que le mien
mon% s; code>.
de la coquille, cela fonctionne:
cat test.txt | while read line ; do echo $line | sed -e 's/./&\n/g' | sort | uniq | sed -e :a -e '$!N; s/\n//; ta' ; done
Ceci ressemble à une application classique de la vue positive, mais malheureusement, Perl ne supporte pas cela. En fait, le faire (correspondant au texte précédent d'un caractère dans une chaîne avec une regex complète dont la longueur est indéterminable) ne peut être effectuée que sur des classes de regex .net, je pense.
Cependant, Lookahead positif soutient des expulsions complètes, donc Tout ce que vous avez à faire est d'inverser la chaîne, appliquez un lookahead positif (comme unicornaddict dit): p> et inversez-le, car sans l'inverse qui ne conserve que le double caractère à la dernière place dans une ligne. p> Massive Modification forte> P> Je passe la dernière demi-heure à ce sujet, et cela ressemble à ceci Fonctionne, Je ne sais pas s'il faut être fier ou horrible. Je fais essentiellement la looakahead positive, puis remplacez sur la chaîne avec \ g spécifiée - ce qui rend le moteur de regex démarrer sa correspondance de la dernière place correspondée (représentée en interne de la variable POS ()). P> Avec une entrée de test comme ceci: p> AABBBCBBCCBABB P>
efauuuuh p>
abcbbbbd p>
DEEEFGGH P>
AABBCC P>
blockQuote> La sortie est comme ceci: p> abc p>
efauh p>
abcd p>
DEFGH P>
abc p>
blockQuote> i pense em> Ça fonctionne ... p> Explication em> - D'accord, au cas où mon explication n'était pas assez claire - Le lookahead ira et s'arrêtera au dernier match d'une variable en double [dans le code, vous pouvez faire un POS d'impression (); À l'intérieur de la boucle pour vérifier] et le S / \ g // G supprimera-le [Vous n'avez pas besoin de / g vraiment]. Donc, dans la boucle, la substitution continuera à éliminer jusqu'à ce que tous ces doublons soient zappés. Bien sûr, cela pourrait être un peu trop processeur intensif pour vos goûts ... mais la plupart des solutions à base de regex que vous verrez. La méthode d'inversion / lookahead sera probablement plus efficace que cela, cependant. P> P>
Plus précisément, c'est la longueur de la variable i> lookbehinds perl ne prend pas en charge. Outre .NET, ils sont pris en charge par JGSoft (EditPad Pro, PowerGrep) et dans une forme plus limitée de Java.
Édité et ajouté une nouvelle solution. Je ne sais pas si c'est complet ou non ... trop de caféine. :-P
Si l'ensemble de caractères pouvant être rencontrés est restreint, par exemple Seules les lettres, alors la solution la plus facile sera avec TR <
Perl -P -E 'TR / A-ZA-Z / A-ZA-Z / S' CODE>
Il remplacera toutes les lettres par elles-mêmes, laissant d'autres caractères non affectés et / s modifier va transmettre des occurrences répétées du même caractère (après le remplacement), éliminant ainsi des doublons p>
Voici une solution, que je pense devoir travailler plus vite que la lookahead, mais elle n'est pas à la fois basée sur la réégalité et utilise hashtable.
perl -n -e '%seen=();' -e 'for (split //) {print unless $seen{$_}++;}'
EFUAH UEH UJHACDEF
Si Perl n'est pas un must, vous pouvez également utiliser AWK. Voici une référence amusante sur le Perl One Liners posté contre Awk. Awk est 10+ secondes plus rapidement pour un fichier avec 3Million ++ lignes
Je suis étonné de la rapidité avec laquelle la solution Regexp est rapide