2010-07-26 2 views
2

Je cherche un moyen de générer une regex à partir des différences entre deux chaînes d'entrée. L'expression rationnelle peut ensuite être utilisée pour correspondre à la troisième chaîne qui est également similaire aux deux chaînes d'entrée.Générer une expression régulière à partir de diff

Par exemple, avec 3 chaînes: f1, f2 et f3

f1:

111xxx222 

f2:

111yyy222 

f3:

111zzz222 

Je suis se demandant s'il y a une façon générique de générer t oici regex de f1 et f2 qui peut être utilisé pour extraire "zzz" en f3:

111(.*)222 
+0

Voyons voir si je comprends cela. Vous voulez garder la partie "statique" de la chaîne, quelque chose qui est égal dans les chaînes précédentes, l'utiliser pour localiser ce qui est différent via une regex? – Anders

+0

oui, c'est correct. Je voudrais générer un modèle à partir des 2 chaînes d'entrée et l'utiliser pour extraire (ou localiser) les différences dans la 3ème chaîne – defoo

+0

111 (. *) 222 devrait probablement être 111 (. *?) 222. Il serait utile que vous fournissiez des exemples un peu plus réels que ceux-ci et expliquiez le contexte de votre demande. Qu'essayez-vous de faire? – Sylverdrag

Répondre

1

En supposant que les 2 chaînes sont de longueur égale, avec Perl, vous pouvez faire:

my @x = split//,'111xxx222'; 
my @y = split//,'111yyy222'; 
my $r; 
for my $i(0..$#x) { 
    $r .= $x[$i] eq $y[$i] ? $x[$i] : '.'; 
} 
$r =~ s/(\.+)/($1)/g; 
print $r 

sortie:

111(...)222 
0

Il y a probablement beaucoup plus agréable façon de le faire, mais, en Python:

import re 

f1 = "111xxx222" 
f2 = "111yyy222" 
f3 = "111zzz222" 

pre = [] 
post = [] 
found_diff = 0 

for i in range(len(f1)): 
    if f1[i] == f2[i]: 
     if found_diff == 0: 
      pre.append(f1[i]) 
     else: 
      post.append(f1[i]) 
    else: 
     found_diff = 1 

regex = "".join(pre) + "(.*)" + "".join(post) 

re.compile(regex) 
print re.match(regex, f3).group(1) 

imprime zzz. NB: cela ne fonctionnera pas si les deux premières chaînes n'ont pas la même longueur.

2

Now you have two problems.

Vous devez réfléchir sérieusement à l'ensemble des chaînes possibles et quelle est l'expression régulière «correcte» pour chaque paire d'entrées. Je sais que cela vous semble évident en ce moment, mais convaincre votre algorithme de faire ce que vous attendez pourrait être plus difficile que vous ne le pensez. Un petit TDD est toujours une bonne idée: essayez de penser à des cas pathologiques.

Dans votre exemple, pourquoi il ne devrait pas générer quelque chose comme l'un de ceux-ci, au lieu de votre suggestion (voir @ réponse de M42 pour la première) ?:

111(...)222 
111(...*)222 
111(...+)222 
111(..*)222 
111(...?)222 
(.*)111(.*)222(.*) 
etc. 

Que voulez-vous arriver si la troisième chaîne est l'un d'entre eux? Ou le second?

1111zzz222 
111zzz2222 
0111zzz222 
111zzz2223 
111zzzz222 
111zz222 
11zzz222 
111zzz22 
111zzz 
zzz222 
111xyz222 
1z1z1z222 
111222 
1111222 
1112222 
etc. 

Si (comme je le soupçonne) vous savez déjà que certains de ces cas vont être impossible, alors vous savez déjà plus sur la structure possible des chaînes que vous laisser sur. Et si c'est le cas, vous devriez probablement juste analyser les ficelles et l'avoir fait.

Si vous voulez vraiment vraiment essayer de toute façon, alors la première chose à savoir est si vous voulez faire correspondre "longest common subsequence" ou une variation de "longest common substring".

Si vous avez vraiment êtes courir ce contre des chaînes arbitraires, alors une fois que vous pensez que vous avez un bon algorithme, assurez-vous de le tester contre beaucoup des données d'échantillon (qui devrait être assez facile de générer ...

+0

s'il vous plaît donner le "deux problèmes" citer un repos. Il n'aide pas les débutants, et le reste d'entre nous l'ont déjà entendu: http://www.google.com/search?hl=fr&as_qdr=all&q="now+(the++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ problèmes "+ site% 3Astackoverflow.com –

+0

@Alan: toute critique sur le reste de ma réponse? Pensez-vous que le PO est à 100% sur la bonne voie avec cette approche «générer moi-un-regex»? J'ai seulement utilisé la citation dans un endroit que je peux me rappeler (à savoir: sur cette page), et puisque je pense que c'est exactement et précisément au point dans ce cas particulier, j'attendrai de me reposer jusqu'à ce que je J'ai l'impression d'avoir trop manqué. Jusque-là, voici un lien vers une page qui décrit très bien mes propres pensées sur les expressions régulières: http://www.codinghorror.com/blog/2008/06/regular-expressions-now-you-have-two-problems. html –

+1

Je ne voulais pas dire que * vous * l'aviez surexploité, juste que ça a déjà été fait à mort. Commencer une réponse avec un zinger usé tend à rendre l'auteur sonnant ignorant et préjudiciable, ce qui est malheureux dans ce cas, puisque c'est en fait une bonne réponse. –

0

La librairie std lib Python inclut un module diff, difflib. Voici un coup de couteau à votre problème:

>>> import difflib 
>>> f1 = "111xxx222" 
>>> f2 = "111yyy222" 
>>> sm = difflib.SequenceMatcher(a=f1, b=f2) 
>>> diff_re = '' 
>>> for a,b,n in sm.get_matching_blocks(): 
... if not n: continue 
... if diff_re: diff_re += "(.*)" 
... diff_re += f1[a:a+n] 
... 
>>> print diff_re 
'111(.*)222' 
0

Je pense que cela est un problème très intéressant, surtout si elle est généralisée à quelque chose comme « cordes N données, trouver le plus simple, regex la plus restrictive R qui les correspond ». Dans les données de test fournies, cela donnerait probablement des réponses inutiles comme "111 (xxx | yyy) 222", donc la question devra peut-être être affinée.

Cela ne sonne comme le genre de question compsci pure qui aurait dû avoir un document écrit à ce sujet ...

Questions connexes