Je travaille sur une routine pour supprimer les commentaires de bloc ou de ligne de certains codes C #. J’ai regardé les autres exemples sur le site, mais je n’ai pas trouvé la réponse exacte que je cherche.
Je peux faire correspondre les commentaires de bloc (/ * commentaire * /) dans leur intégralité en utilisant cette expression régulière avec RegexOptions.Singleline:
(/\*[\w\W]*\*/)
Et je peux faire correspondre les commentaires de ligne (// comment) dans leur intégralité en utilisant cette expression régulière avec RegexOptions.Multiline:
(//((?!\*/).)*)(?!\*/)[^\r\n]
Remarque: j’utilise [^\r\n]
au lieu de $
car $
inclut également \r
dans la correspondance.
Cependant, cela ne fonctionne pas comme je le souhaite.
Voici mon code de test auquel je correspond:
// remove whole line comments bool broken = false; // remove partial line comments if (broken == true) { return "BROKEN"; } /* remove block comments else { return "FIXED"; } // do not remove nested comments */ bool working = !broken; return "NO COMMENT";
L’expression de bloc correspond
/* remove block comments else { return "FIXED"; } // do not remove nested comments */
ce qui est bien et bon, mais l’expression de la ligne correspond
// remove whole line comments // remove partial line comments
et
// do not remove nested comments
En outre, si je ne dispose pas du style de lecture * / positive dans l’expression de ligne deux fois, il correspond
// do not remove nested comments *
ce que je ne veux vraiment pas.
Ce que je veux, c’est une expression qui corresponde aux caractères, en commençant par //
, jusqu’à la fin de la ligne, mais ne contient pas */
entre la //
et la fin de la ligne.
Aussi, juste pour satisfaire ma curiosité, quelqu’un peut-il expliquer pourquoi j’ai besoin de deux fois la tête de lecture? (//((?!\*/).)*)[^\r\n]
et (//(.)*)(?!\*/)[^\r\n]
comprendront tous les deux le * , mais (//((?!\*/).)*)(?!\*/)[^\r\n]
et (//((?!\*/).)*(?!\*/))[^\r\n]
ne sera pas.
Vos deux expressions régulières (pour les commentaires de bloc et de ligne) ont des bogues. Si vous voulez, je peux décrire les bugs, mais je pense que c’est peut-être plus productif si j’en écris de nouveaux, surtout parce que j’ai l’intention d’écrire un seul qui corresponde aux deux.
La chose est, chaque fois que vous avez /*
et //
et les chaînes littérales «interférer» les uns avec les autres, c’est toujours celui qui commence en premier qui a la priorité. C’est très pratique car c’est exactement ainsi que fonctionnent les expressions régulières: recherchez d’abord la première correspondance.
Définissons donc une expression régulière qui correspond à chacun de ces quatre jetons:
var blockComments = @"/\*(.*?)\*/"; var lineComments = @"//(.*?)\r?\n"; var ssortingngs = @"""((\\[^\n]|[^""\n])*)"""; var verbatimSsortingngs = @"@(""[^""]*"")+";
Pour répondre à la question dans le titre (commentaires de bandes), il faut:
Regex.Replace
peut le faire facilement en utilisant une fonction MatchEvaluator:
ssortingng noComments = Regex.Replace(input, blockComments + "|" + lineComments + "|" + ssortingngs + "|" + verbatimSsortingngs, me => { if (me.Value.StartsWith("/*") || me.Value.StartsWith("//")) return me.Value.StartsWith("//") ? Environment.NewLine : ""; // Keep the literal ssortingngs return me.Value; }, RegexOptions.Singleline);
J’ai exécuté ce code sur tous les exemples fournis par Holystream et sur divers autres cas auxquels je pouvais penser, et cela fonctionne comme un charme. Si vous pouvez fournir un exemple où il échoue, je suis heureux d’ajuster le code pour vous.
Avant de l’implémenter, vous devrez d’abord créer des scénarios de test.
Il y a probablement plus de cas là-bas.
Une fois que vous les avez tous, vous pouvez créer une règle d’parsing pour chacun d’eux ou en regrouper certains.
Résoudre cela avec une expression régulière seule sera probablement très difficile et sujette à erreur, difficile à tester et difficile à maintenir par vous et les autres programmeurs.
Vous pouvez numéroter le code avec une expression comme:
@(?:"[^"]*")+|"(?:[^"\n\\]+|\\.)*"|'(?:[^'\n\\]+|\\.)*'|//.*|/\*(?s:.*?)\*/
Cela correspondrait également à certaines structures / échappements non valides (par exemple, 'foo'
), mais correspondrait probablement à tous les jetons d’intérêt (sauf si j’ai oublié quelque chose), ce qui fonctionne bien pour un code valide.
En l’utilisant dans un remplacement et en capturant les pièces que vous souhaitez conserver, vous obtiendrez le résultat souhaité. C’est à dire:
static ssortingng SsortingpComments(ssortingng code) { var re = @"(@(?:""[^""]*"")+|""(?:[^""\n\\]+|\\.)*""|'(?:[^'\n\\]+|\\.)*')|//.*|/\*(?s:.*?)\*/"; return Regex.Replace(code, re, "$1"); }
Exemple d’application :
using System; using System.Text.RegularExpressions; namespace Regex01 { class Program { static ssortingng SsortingpComments(ssortingng code) { var re = @"(@(?:""[^""]*"")+|""(?:[^""\n\\]+|\\.)*""|'(?:[^'\n\\]+|\\.)*')|//.*|/\*(?s:.*?)\*/"; return Regex.Replace(code, re, "$1"); } static void Main(ssortingng[] args) { var input = "hello /* world */ oh \" '\\\" // ha/*i*/\" and // bai"; Console.WriteLine(input); var noComments = SsortingpComments(input); Console.WriteLine(noComments); } } }
Sortie:
hello /* world */ oh " '\" // ha/*i*/" and // bai hello oh " '\" // ha/*i*/" and
J’ai trouvé celui-ci sur http://gskinner.com/RegExr/ (nommé “.Net Comments aspx”)
(//[\t|\s|\w|\d|\.]*[\r\n|\n])|([\s|\t]*/\*[\t|\s|\w|\W|\d|\.|\r|\n]*\*/)|(\<[!%][ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t%]*)\>)
Lorsque je le teste, il semble supprimer tous les // commentaires et / * commentaires * / comme il se doit, laissant ces guillemets derrière.
Je ne l’ai pas beaucoup testé, mais semble fonctionner plutôt bien (même si c’est une ligne de regex horrible et monstrueuse).
Voir aussi mon projet de minification du code C #: CSharp-Minifier
En dehors de la suppression des commentaires, des espaces et des sauts de ligne du code, il est actuellement capable de compresser les noms de variables locales et d’effectuer d’autres minifications.
pour bloc Commentaires (/ * … * /) vous pouvez utiliser cette exp:
/\*([^\*/])*\*/
cela fonctionnera aussi avec des commentaires multilignes.