J'ai besoin de construire une regex (syntaxe .NET) pour déterminer si une chaîne se termine par une valeur spécifique. Spécifiquement, j'ai besoin de tester si un fichier a une extension spécifique (ou un ensemble d'extensions).
Le code que j'essaie de corriger utilisait: p> qui est hideusement lent pour les correspondances défaillantes dans mon scénario (probablement en raison de la backtracking. p> Supprimer simplement le Il se sent toujours comme il est assez inefficace. Je manque quelque chose d'évident ici? P> Malheureusement, je ne contrôle pas le API en question Donc, j'ai besoin d'une regex pour le faire, même si je ne voudrais normalement pas envisager de regex d'être le bon outil pour le travail. P> J'ai aussi fait des tests en utilisant le . * code> (qui va bien depuis que l'API ne teste que pour les allumettes et n'entraîne pas n'importe quoi) au début rend la regex beaucoup plus efficace. P> Regexoption.righttoleft < / code> et constaté que je pouvais épermettre un peu plus de performances de mon étui à tester avec ^. * \. (png | jpg | gif) $ code>, mais je ne trouve pas de moyen de spécifier l'option code> de droite code> dans la chaîne de la regex elle-même, donc je ne pense pas Je peux l'utiliser. P> P>
5 Réponses :
Vous n'avez probablement pas besoin d'une expression régulière pour cela ... mais allez avec la question initiale: p>
Assurez-vous que vous utilisez RegExoptions.Compilé pour pré-compiler l'expression régulière, puis réutilisez votre objet Regex. Cela évite de configurer la regex à chaque fois que vous l'utilisez, cela accélérera beaucoup les choses. P>
@Nowyouhavetwoproblèmes: Pourriez-vous tester la solution de SOAPBOX et nous dire comment se compare à votre approche, s'il vous plaît?
Étant donné qu'il ne peut pas envoyer l'option code> DroiteToleft CODE>, il ne pourra pas envoyer l'option code> compilée code>.
@Blixt est juste ici. Tout ce que je peux faire, c'est passer dans une chaîne qui sera interprétée comme une regex de l'autre côté.
Si vous pouvez changer em> le code, pourquoi ne pouvez-vous pas utiliser autre chose? Vous ne contrôlez pas l'API, à droite, mais vous le changez de toute façon. Ce que je ne comprends vraiment pas. Quoi qu'il en soit, pourquoi pas simplement: p> var AcceptedExtensions = new List<string>() { "txt", "html", "htm" };
var extension = filename.Substring(filename.LastIndexOf(".") + 1).ToLower();
return AcceptedExtensions.Contains(extension);
Ouais c'est la façon évidente de le faire, mais je suis sûr qu'il est coincé avec une API qui prend une chaîne qui est traitée comme une expression régulière.
Certes, et j'aimerais pouvoir utiliser une approche à base de cordes plutôt que surgènes, mais je n'ai pas cette option dans ce cas.
Pourquoi dites-vous que vous n'avez pas l'option? Une option est le code ci-dessus. Pourquoi ne pouvez-vous pas l'utiliser?
@Bruno Reis: Imaginez qu'il doit utiliser une API comme: ProcessFiles (
@slebetman, cela me semble la seule réponse possible. Mais c'est toujours bizarre. Si nous savions plus précisément quelles sont les restrictions, peut-être qu'une meilleure solution pourrait émerger!
@Bruno Reis: Nous savons précisément quelles sont les restrictions. Il l'a dit dans son poste: "Je ne contrôle pas l'API en question, donc j'ai besoin d'une regex pour le faire, même si je ne considérerais pas normalement que le regex soit le bon outil pour le travail" Code> . Cela signifie qu'il doit appeler une fonction qui accepte une chaîne (pourquoi pas un objet Regexp, je n'ai aucune idée) et interprète cette chaîne en tant que regexp. Il ne peut pas changer la source de cette fonction. Il demande une bonne réégycade de passer à cette fonction.
Écrivez spécifiquement pour une période plutôt que n'importe quel caractère précédant l'extension: Cela le rendra plus sûr (ne correspondra pas à x.xgif) et il n'aura pas à faire tout reculant du tout jusqu'à ce qu'il ait trouvé une période (par opposition à la mise en marche de tous les personnages). p> p>
Mon regex original a le point littéral, mais il s'est perdu dans le balisage lorsque j'ai posté ici.
Je n'ai pas accès à C # afin que je ne puisse pas essayer ceci ... mais vous devriez être capable d'éviter trop de backtracking en forçant le moteur pour trouver d'abord la fin de la chaîne, puis correspondant aux extensions: < Pré> xxx pré>
Je ne suis pas sûr de l'effet que le look-derrière a sur la performance, cependant. p> p>
De mes tests préliminaires, il s'agit d'environ 2 fois plus vite que l'approche que j'utilisais et à peu près au pair avec la droite correspondante que je faisais dans mon application de test. Je suppose que cela a du sens parce qu'il écrit essentiellement l'expression comme une voix droite
D'accord, bon à savoir! Je suis à peu près sûr que certains moteurs d'expression réguliers effectuent des optimisations dans la phase de compilation lorsqu'elles voient le (code> $ code> ancreur, en veillant à commencer à vérifier à la fin de la chaîne, mais évidemment le moteur d'expression ordinaire .NET. ne pas.
J'ai remarqué que quelqu'un a baissé ma réponse, mais je ne me soucie pas d'expliquer pourquoi ... ce genre de bownvote inutile, n'est-ce pas? S'il vous plaît, expliquez toujours pourquoi vous avez indiqué quelque chose.
Vraiment, vous pouvez également déposer à tout simplement surgèrent et utiliser string.endswidth code>, avec les suivants: var extensions = new String[] { ".png", ".jpg", ".gif" };
extensions.Any(ext => "something".EndsWith(ext));
Sur un autre, peut-être trop biaisé, note, je pense que regex sont en réalité des lutins diaboliques qui essaient de dépasser votre cerveau.
De quelle magnitude est la lenteur de
\. (Png | jpg | gif) $ code>, car je pense que c'est le plus simple que vous obtiendrez avec des expressions régulières. Le reste est à la mise en œuvre.Pourquoi ne pas simplement boucle via la matrice des extensions valides et utiliser
.wswith code>? La comparaison de chaîne simple est beaucoup plus rapide qu'un moteur de regex.À quelle vitesse faut-il? À Ruby, l'une des langues les plus lentes autour, je peux comparer 348 000 chemins par seconde. Je choisirais la plus simple regexp non parce que c'est plus rapide, mais parce qu'il est plus facile de lire et de comprendre.
@Wayne: Il est plus facile de lire et de comprendre seulement si i> vous êtes toujours verrouillé à quelques extensions. Et si plus tard, vous voulez prendre en charge
BMP code>?TIF CODE>?TIFF CODE>?apng code>? Ou pour corriger queJPEG code> est également une extension JPEG largement utilisée? Votre regex devient bientôt dans un monstre à 1 linger qui est difficile àDiff Code>, mon tableau est toujours maintenu et compréhensible.@Kenny, bon point. En rubis, des expressions régulières peuvent être construites de cordes assez facilement. Cela coulent certainement de ma perception de ce qui est facile et ce qui est difficile. En commençant par une gamme d'extensions, on peut accéder à une expression régulière aussi simplement que celle-ci: Regexp.new ('. + extensions.join (' | ') +' $ '). Si une regex peut être faite d'une chaîne en C #, la même technique (syntaxe différente) peut être utilisée.
Je remarque que la seconde regex de votre question commence par le
^ code> l'ancre tandis que le premier ne le fait pas. Avez-vous en fait essayé les deux manières? Je m'attendrais à ce que la version ancrée échoue beaucoup plus rapidement lorsque aucune correspondance n'est possible.