29 votes

Regex à la bande de commentaires en ligne à partir de C#

Je suis en train de travailler sur une routine de bande de bloquer ou de commentaires en ligne à partir d'un code C#. J'ai regardé les autres exemples sur le site, mais n'ai pas trouvé l' exacte réponse que je cherche.

Je peux correspondre à bloquer les commentaires (/* commentaire */) dans leur intégralité à l'aide de cette expression régulière avec RegexOptions.Singleline:

(/\*[\w\W]*\*/)

Et je peux correspondre à la ligne de commentaires (// commentaire) dans leur intégralité à l'aide de cette expression régulière avec RegexOptions.Multiline:

(//((?!\*/).)*)(?!\*/)[^\r\n]

Note: je suis à l'aide d' [^\r\n] au lieu de $ car $ y \r dans le match, trop.

Cependant, ce n'est pas tout à fait travailler la façon dont je le veux.

Voici mon code de test que je suis la correspondance contre:

// 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";

Le bloc de l'expression correspond à

/* remove block comments
else
{
    return "FIXED";
} // do not remove nested comments */

ce qui est bien et bon, mais la ligne de l'expression correspond à

// remove whole line comments
// remove partial line comments

et

// do not remove nested comments

Aussi, si je n'ai pas l' */ anticipation positif dans la ligne de l'expression deux fois, il correspond à

// do not remove nested comments *

qui j'ai vraiment ne voulez pas.

Ce que je veux, c'est une expression qui correspond à des caractères, en commençant par //, à la fin de la ligne, mais ne pas contenir */ entre l' // et à la fin de la ligne.

Aussi, juste pour satisfaire ma curiosité, quelqu'un peut-il expliquer pourquoi j'ai besoin de l'anticipation deux fois? (//((?!\*/).)*)[^\r\n] et (//(.)*)(?!\*/)[^\r\n] permettra à la fois d'inclure l' *, mais (//((?!\*/).)*)(?!\*/)[^\r\n] et (//((?!\*/).)*(?!\*/))[^\r\n] ne sera pas.

49voto

Timwi Points 30896

Deux de vos expressions régulières (pour le bloc et de commentaires en ligne) ont des bugs. Si vous voulez je peux décrire les bugs, mais je sentais que c'est peut-être plus productif si j'écris des nouvelles, surtout parce que j'ai l'intention d'écrire un seul qui correspond à la fois.

Le truc, c'est que chaque fois que vous avez /* et // et les chaînes littérales "d'interférence" les uns avec les autres, c'est toujours celui qui part le premier qui l'emporte. C'est très pratique parce que c'est exactement la façon dont les expressions régulières de travail: trouver le premier match de la première.

Donc, nous allons définir une expression régulière qui correspond à chacun de ces quatre jetons:

var blockComments = @"/\*(.*?)\*/";
var lineComments = @"//(.*?)\r?\n";
var strings = @"""((\\[^\n]|[^""\n])*)""";
var verbatimStrings = @"@(""[^""]*"")+";

Pour répondre à la question dans le titre (supprimer les commentaires), nous avons besoin de:

  • Remplacer le bloc de commentaires avec rien
  • Remplacez la ligne des commentaires avec un saut de ligne (parce que la regex mange le retour à la ligne)
  • Garder des chaînes de caractères littérales où ils sont.

Regex.Replace pouvez le faire facilement à l'aide d'un MatchEvaluator fonction:

string noComments = Regex.Replace(input,
    blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
    me => {
        if (me.Value.StartsWith("/*") || me.Value.StartsWith("//"))
            return me.Value.StartsWith("//") ? Environment.NewLine : "";
        // Keep the literal strings
        return me.Value;
    },
    RegexOptions.Singleline);

J'ai couru ce code sur tous les exemples que Holystream fournie et de nombreuses autres affaires que je pouvais penser, et il fonctionne comme un charme. Si vous pouvez fournir un exemple où il échoue, je suis contente d'ajuster le code pour vous.

4voto

Holystream Points 702

Avant de vous le mettre en œuvre, vous aurez besoin de créer des cas de test pour sa première

  1. De simples commentaires /* */, //, ///
  2. Les commentaires multilignes /* Cette\nis\na\ntest*/
  3. Commentaires après la ligne de code var a = "pomme"; // test ou /* test */
  4. Les commentaires dans les commentaires /* Il // est un test /, ou // Cette / est un test */
  5. Simple non commentaires qui ressemblent à des commentaires, et apparaît entre guillemets var commentaire= "/* Ceci est un test*/", ou la var url = "http://stackoverflow.com";
  6. Complexe et non des commentaires qui ressemblent à des commentaires: var abc = @" c' /* \n est un commentaire d'une citation\n*/", avec ou sans espace entre " et /* ou */ et "

Il y a probablement plus de cas là-bas.

Une fois que vous avez tous d'entre eux, alors vous pouvez créer une analyse de la règle pour chacun d'eux, de groupe ou de certains d'entre eux.

La résolution de ce avec expression régulière probablement tout seul sera très difficile et sujette à erreur, il est difficile de tester, et difficile à maintenir par vous et par d'autres programmeurs.

2voto

Qtax Points 20487

Vous pourriez marquer le code avec une expression comme:

@(?:"[^"]*")+|"(?:[^"\n\\]+|\\.)*"|'(?:[^'\n\\]+|\\.)*'|//.*|/\*(?s:.*?)\*/

Il serait également correspondre à certains invalides s'échappe/structures (par exemple. 'foo'), mais il sera probablement correspondre à tous les jetons valides d'intérêt (sauf si j'ai oublié quelque chose), donc bien pour le code valide.

En l'utilisant dans une remplacer et de capturer les pièces que vous voulez garder vous donnera le résultat souhaité. I. e:

static string StripComments(string 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 string StripComments(string code)
        {
            var re = @"(@(?:""[^""]*"")+|""(?:[^""\n\\]+|\\.)*""|'(?:[^'\n\\]+|\\.)*')|//.*|/\*(?s:.*?)\*/";
            return Regex.Replace(code, re, "$1");
        }

        static void Main(string[] args)
        {
            var input = "hello /* world */ oh \" '\\\" // ha/*i*/\" and // bai";
            Console.WriteLine(input);

            var noComments = StripComments(input);
            Console.WriteLine(noComments);
        }
    }
}

Sortie:

hello /* world */ oh " '\" // ha/*i*/" and // bai
hello  oh " '\" // ha/*i*/" and

0voto

einord Points 159

J'ai trouvé celui-ci à http://gskinner.com/RegExr/ (nommé ".Net Commentaires 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%]*)\>)

Quand je l'ai tester il semble pour supprimer tous // les commentaires et /* commentaires */ comme il se doit, en laissant à l'intérieur des guillemets derrière.

N'ai pas testé beaucoup, mais semble fonctionner assez bien (même si c'est un horrible, monstrueux ligne de regex).

0voto

Guy Points 624

pour bloquer les Commentaires (/* ... */) vous pouvez utiliser cette exp:

/\*([^\*/])*\*/

il travaillera avec les commentaires de plusieurs lignes aussi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X