2010-04-14 3 views
4

J'apprends enfin les regexps et je m'entraine avec ack. Je crois que cela utilise Perl regexp.Pourquoi ai-je des résultats inattendus supplémentaires avec mon ack regex?

Je veux faire correspondre toutes les lignes où les premiers caractères non vides sont if (<word> !, avec un nombre quelconque d'espaces entre les éléments.

C'est ce que je suis venu avec:

^[ \t]*if *\(\w+ *! 

Il ne presque travaillé. ^[ \t]* est faux, car il correspond à un ou aucun [espace ou tabulation]. Ce que je veux est de faire correspondre tout ce qui peut contenir seulement de l'espace ou une tabulation (ou rien).

Par exemple ils ne doivent pas correspondre:

// if (asdf != 0) 
else if (asdf != 1) 

Comment puis-je modifier mon regexp pour cela?


EDIT ajoutant la ligne de commande

ack -i --group -a '^\s*if *\(\w+ *!' c:/work/proj/proj 

Notez les guillemets simples, je ne suis pas si sûr d'eux plus.

Ma base de recherche est une base de code plus grande. Il ne comprend les expressions correspondant (assez peu), mais même par exemple:

274:    }else if (y != 0) 

, que je reçois à la suite de la commande ci-dessus.


EDIT en ajoutant le résultat du test

de Mobrule de mobrule, merci de me fournir un texte à tester sur. Je vais copier ici ce que je reçois sur mon invite:

C:\Temp\regex>more ack.test 
# ack.test 
if (asdf != 0) # no spaces - ok 
if (asdf != 0) # single space - ok 
    if (asdf != 0) # single tab - ok 
    if (asdf != 0) # multiple space - ok 
     if (asdf != 0) # multiple tab - ok 
    if (asdf != 0) # spaces + tab ok 
    if (asdf != 0) # tab + space ok 
    if (asdf != 0) # space + tab + space ok 
// if (asdf != 0) # not ok 
} else if (asdf != 0) # not ok 

C:\Temp\regex>ack '^[ \t]*if *\(\w+ *!' ack.test 

C:\Temp\regex>"C:\Program\git\bin\perl.exe" C:\bat\ack.pl '[ \t]*if *\(\w+ *!' a 
ck.test 
if (asdf != 0) # no spaces - ok 
if (asdf != 0) # single space - ok 
    if (asdf != 0) # single tab - ok 
    if (asdf != 0) # multiple space - ok 
     if (asdf != 0) # multiple tab - ok 
    if (asdf != 0) # spaces + tab ok 
    if (asdf != 0) # tab + space ok 
    if (asdf != 0) # space + tab + space ok 
// if (asdf != 0) # not ok 
} else if (asdf != 0) # not ok 

Le problème est dans mon appel à mon ack.bat!

ack.bat contient:

"C:\Program\git\bin\perl.exe" C:\bat\ack.pl %* 

Bien que je l'appelle avec un accent circonflexe, il se éloigne à l'appel du fichier de chauve-souris!

L'échappement du curseur ^^ ne fonctionne pas.

En citant la regex avec " " au lieu de ' ' fonctionne. Mon problème était un problème de DOS/win, désolé de vous déranger tous pour cela.

+0

Comme mobrule a dit dans sa réponse, votre regex semble correct pour que vous avez décrit le comportement souhaité. Pouvez-vous modifier votre question pour inclure des exemples de données, la ligne de commande ack que vous utilisez et votre sortie souhaitée? –

+0

Si ce n'est déjà fait, lisez perlrequick (perlrequick, perldoc perlrequick, ou trouvez-le en ligne). Après cela, si vous voulez des fonctionnalités plus avancées, lisez perlre. En tout cas, je recommande fortement de maîtriser les expressions régulières d'O'Reilly. – kbenson

Répondre

4

À la fois ack et grep, * correspond à zéro ou plus, et non à zéro ou un. Donc je pense que vous avez déjà la bonne solution. Quels cas de test ne vous donnent pas les résultats que vous voulez?

# ack.test 
if (asdf != 0) # no spaces - ok 
if (asdf != 0) # single space - ok 
    if (asdf != 0) # single tab - ok 
    if (asdf != 0) # multiple space - ok 
     if (asdf != 0) # multiple tab - ok 
    if (asdf != 0) # spaces + tab ok 
    if (asdf != 0) # tab + space ok 
    if (asdf != 0) # space + tab + space ok 
// if (asdf != 0) # not ok 
} else if (asdf != 0) # not ok 

Résultats:

$ ack '^[ \t]*if *\(\w+ *!' ack.test 
if (asdf != 0) # no spaces - ok 
if (asdf != 0) # single space - ok 
     if (asdf != 0) # single tab - ok 
    if (asdf != 0) # multiple space - ok 
       if (asdf != 0) # multiple tab - ok 
     if (asdf != 0) # spaces + tab ok 
     if (asdf != 0) # tab + space ok 
     if (asdf != 0) # space + tab + space ok 

$ ack -v '^[ \t]*if *\(\w+ *!' ack.test 
// if (asdf != 0) # not ok 
} else if (asdf != 0) # not ok 
+0

@mobrule - à la fois la page d'accueil ack et la question OP a déclaré que ack utilise Perl regex, pas la variété Grep. – DVK

+0

'} else if (y! = 0) {' est dans mes résultats. Notez que j'utilise un guillemet simple autour de l'expression dans la ligne de commande, cela pourrait-il être lié à mon problème? – Gauthier

6
^\s*if\s*\(\S+\s*! 
  • Utilisation \S pour l'espace non-blanc. \w ne correspondra à aucun caractère spécial, donc if ($word ne correspondra pas.Peut-être est OK avec vos spécifications, auquel cas \w (alphanumérique plus "_" ) est OK
 
$ perl5.8 -e '{$s="else if (asdf \!= 1)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";}}' 
NO MATCH 
$ perl5.8 -e '{$s="// if (asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";}}' 
NO MATCH 
$ perl5.8 -e '{$s=" if (asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";}}' 
|asdf| 
$ perl5.8 -e '{$s="if (asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";}}' 
|asdf| 
$ perl5.8 -e '{$s="if (\$asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";}}' 
|$asdf| 
+0

Veuillez ignorer le backslash devant "!" dans mes exemples, c'est pour le shell Unix. En interne à Perl, ce serait juste "!" – DVK

+0

Même ici. Il semble juste que '^' ne fonctionne pas! – Gauthier

+0

Et oui, j'ai eu ack.bat quelque part, et il semble supprimer le caractère '^'! (voir mon post édité). – Gauthier

1

Vous pouvez essayer:

(?:\t*| *)if *\(\w+ *! 

.

\t*| * 

sera égal à zéro ou plusieurs onglets ou zéro ou plusieurs espaces non un mélange des espaces et des onglets.

Questions connexes