2010-03-30 6 views
3

Votre tâche, si vous choisissez de l'accepter, consiste à écrire une expression régulière Perl qui, pour une chaîne donnée, renverra la première occurrence d'un caractère qui n'est pas dupliqué de manière consécutive. En d'autres termes, les deux ont précédé ET réussi par des caractères différents de lui-même (respectivement début/fin de chaîne).Qu'est-ce qu'une expression rationnelle Perl pour trouver le premier caractère non répétitif dans une chaîne?

Exemple:

IN: aabbcdecc 
OUT: c 

S'il vous plaît noter que « non consécutivement dupliquée » ne signifie pas « nulle part dans la chaîne ».

REMARQUE: il doit s'agir d'une expression regex pure. Par exemple. la solution qui vient évidemment à l'esprit (cloner la chaîne, supprimer tous les doublons et imprimer le premier caractère restant) ne compte pas, bien qu'elle résout le problème.

La question est inspirée par ma réponse un peu hors-sujet à ceci: How can I find the first non-repeating character in a string using Perl?

Répondre

2
(?:(.)\1+)*(.?) 

Obtenez le 2ème capture. (Renverra une chaîne vide si chaque caractère est reproduit consécutivement.)

cas de test:

~:2434$ perl -e "\"abc\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
a 
~:2435$ perl -e "\"aabbcc\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 

~:2436$ perl -e "\"aabbc\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
c 
~:2437$ perl -e "\"aabcc\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
b 
~:2438$ perl -e "\"aabcbbbcccccc\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
b 
~:2439$ perl -e "\"aabbvbbcccccc\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
v 
~:2440$ perl -e "\"aabbcdecc\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
c 
~:2441$ perl -e "\"aabbccddeef\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
f 
~:2442$ perl -e "\"faabbccddeef\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
f 
~:2443$ perl -e "\"faabbccddeefax\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
f 
~:2444$ perl -e "\"xfaabbccddeefx\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
x 
~:2445$ perl -e "\"xabcdefghai\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
x 
~:2446$ perl -e "\"cccdddeeea12345\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
a 
~:2447$ perl -e "\"1234a5678a23\" =~ m/(?:(.)\1+)*(.?)/; print \$2;" 
1 

Or (. Ne correspondra pas si tous les caractères est consécutivement dupliquée)

(?:^|(.)(?!\1))(.)(?!\2) 
+1

Ne fonctionne pas; (. Les captures étaient "un" et "b". vous laissera à vous de comprendre pourquoi :) – DVK

+1

Celui qui a voté ceci, s'il vous plaît le reprendre - il ne fonctionne pas! – DVK

+0

@Kenny - deuxième essai est beaucoup mieux. Vous avez pris l'erreur rapidement. , mais je suis également bloqué sur "quoi s'il n'y a pas de doublons en amont" – DVK

1
use 5.010; 
$str=~/^(([a-z])\g{-1}+)*(?<c>[a-z])/i; 
$char = $+{c}; 
+0

Incorrect. '[a-z] {2,}' correspond 'abc'. – kennytm

+0

o bon point de connerie – Anon

+0

try now J'ai corrigé – Anon

0

J'aimerais que Perl ait un drapeau regex! à savoir, retourner tous les caractères qui ne correspondent pas/regex/

Ce que vous cherchez est vraiment le complément de capture regex de:

m/(.)(\1)+/ 

J'ai essayé toutes les suggestions sur cette page contre la liste des données de Brian (le résultat de dans sa liste de programme). Aucun ne fonctionne complètement.

l'expression rationnelle de:

(?:^|(.)(?!\1))(.)(?!\2) 

ne parvient pas à correspondre au début « f » à la ligne 2 et 3. Brian de ne correspond pas au « f » au début de la ligne 2 et 3 ou l'une quelconque des singletons à la fin de la ligne 5.

le regex de:

$str=~/^(([a-z])\g{-1}+)*(?<c>[a-z])/i; 
$char = $+{c}; 

fonctionne.

La seule regex seule que j'ai trouvé est simple:

#!/usr/bin/perl 
while(<DATA>) { 
    chomp; 
    print "BEFORE: $_\n"; 
    s/(.)(\1)+//g; 
    print "AFTER: $_\n"; 
    print "charater: " . substr($_,0,1) . "\n\n"; 
} 
__END__ 
aabbccddeef 
faabbccddeef 
faabbccddeefax 
xfaabbccddeefx 
xabcdefghai 
cccdddeeea12345 
1234a5678a23 
aabbcdecc 
abcdefg 
aabbccddeef 
cccdddeeea12345 

Cela fonctionne dans le cas simple de « donner le premier caractère. » ((edit: relire: désolé, je lis maintenant que l'évidence supprime les doubles n'était pas ce que tu cherchais ...))

L'amour à entendre s'il y a une meilleure solution.

+0

Celui-ci semble fonctionner: m/(?: (.) ​​\ 1 +) * (.?)/ – DVK

+0

Ceci: m/(?: (.) ​​\ 1 +) * (.?)/Fonctionne en effet! Même les singletons au début des lignes et dans les groupes sont dans \ 2. Beau puzzle ... – dawg

Questions connexes