2010-03-30 10 views
1

J'essaie d'exécuter un regEXP unix sur chaque fichier journal dans un répertoire de 1,12 Go, puis remplacez le motif correspondant par ''. Test exécuté sur un fichier de 4 meg a pris environ 10 minutes, mais a fonctionné. Évidemment, quelque chose nuit à la performance de plusieurs ordres de grandeur. MISE À JOUR: Je remarque que la recherche de^(155 [0-2]). * $ Prend ~ 7 secondes dans un fichier de 5,6 Mo avec 77 correspondances. Ajout de l'assertion de Lookahead négative,?!, De sorte que le regExp devient^(?! 155 [0-2]). * $ Amène à prendre au moins 5-10 minutes; accordé, il y aura des milliers et des milliers de matches.RegExp de style UNIX Remplacer s'exécutant extrêmement lentement sous Windows. Aidez-moi? EDIT: Affirmation de lookahead négatif impact sur les performances

Est-ce que l'assertion de lookahead négative devrait être extrêmement préjudiciable à la performance quand il y a beaucoup de correspondances?

+0

Quelle est l'utilisation de tous les '. *'? – kennytm

+0

J'utilise.* pour correspondre à 0 occurrences ou plus de n'importe quel caractère .. disant essentiellement "saisir tout le texte avant et après la chaîne de nombre" Je vais me débarrasser de celui qui précède le signe dollar (match de fin de ligne), mais je ne pense que c'est mon goulot d'étranglement ... –

+0

Votre regex dit 155, mais votre texte dit 152. Est-ce une faute de frappe, ou utilisez-vous la mauvaise regex? – Kip

Répondre

0

Si vous pouvez vous débarrasser de ce .* au début, cela aiderait. Que peut-il y avoir avant, juste des espaces? Si oui, essayez:

^(?!\s*155[0-2][0-9]{4}\s).*$ 

Si elle peut vraiment être quelque chose, essayez de faire ce non gourmand:

^(?!.*?155[0-2][0-9]{4}\s).*$ 

Note: dans les deux exemples, j'ai enlevé la deuxième .*, puisque le troisième serait correspondre la même chose aussi bien.

Il est utile de penser à ce que le moteur regex va réellement faire.

  1. Correspondance ^ (début de ligne). Aucun problème. Essayez de faire correspondre l'assertion anticipée négative
  2. Saisissez autant que possible avec .*. Cela signifie qu'il saisit toute la ligne.
  3. Le caractère suivant est-il 1? Si ce n'est pas le cas, faites correspondre .* un caractère de moins et répétez jusqu'à ce qu'il corresponde à 1.

Vous pouvez voir que cela signifie que pour chaque ligne qui ne correspond pas, elle fera marche arrière sur toute la ligne. Maintenant, si vous utilisez simplement \s* au début, alors seulement saisir les espaces, pas toute la ligne. Si cela peut vraiment être quelque chose, .*? sera plus rapide sur les lignes qui correspondent au modèle 155, et ce sera à peu près la même chose sur les lignes qui ne le font pas. Fondamentalement: L'implémentation d'expressions rationnelles que vous utilisez est non-linéaire et ne peut traiter qu'avec un sous-ensemble de la ligne régulière (.* jusqu'à ce qu'elle ait saisi la ligne entière.)

+0

Intéressant ... en plus de votre suggestion, je pense que je peux (en fonction du format de mes fichiers journaux) supprimer [0-9] {4} \ s du regroupement. Cela aide-t-il beaucoup? Actuellement en train d'essayer^(?! \ S * 155 [0-2]). * $, Mais c'est toujours extrêmement lent. :( –

+0

@JohnSullivan: probablement pas beaucoup, puisque ce sont des longueurs fixes.Mon supposer que la cause ultime de la lenteur est que le programme charge le fichier journal entier en mémoire, puis exécute l'expression rationnelle, puis écrit le fichier. Par opposition au traitement d'une ligne à la fois.) – Kip

+1

Il semble que la présence de?!, L'opérateur d'anticipation négatif, est une performance meurtrière (7 secondes à 10 minutes sur 5 Mo, bien que 70 matchs contre 20000). Pensez-vous que nous devrions blâmer le programme, pas la regex? –

0

langage d'expression avec toute efficacité. Voyez ma question au sujet d'un regex implementation that can handle machine generated regexes efficacement pour plus de fond.

Si vous pouvez sélectionner une autre implémentation, vous avez de la chance; Quand je regardais, ils étaient rares. Deux options raisonnables sont RE2 et TRE, mais les deux sont des bibliothèques et non des exécutables autonomes.

Une autre option consiste à utiliser l'utilitaire unix (grep?) Que vous avez utilisé dans le passé; grep a certainement un port Windows comme beaucoup d'autres utilitaires UNIX.