我有一个这样的文本文件

/*
This is a comment
I a looking to delete it
*/
//CALCULATE;
Language([Dim Currency].[Currency].&[4]) = 2057;
Language([Dim Currency].[Currency].&[2]) = 2067;


我已经试过这段代码

var newLines = oldLines.Select(line => new {
                Line = line,
                Words = line.Split("/*")
            })
            .Where(lineInfo => !lineInfo.Words.Contains(wordToDelete))
            .Select(lineInfo => lineInfo.Line);
var newLines1 = oldLines.Select(line => new {
            Line = line,
            Words = line.Split("*/")
        })
        .Where(lineInfo => !lineInfo.Words.Contains(wordToDelete))
        .Select(lineInfo => lineInfo.Line);


代码返回此

This is a comment
I a looking to delete it
//CALCULATE;
Language([Dim Currency].[Currency].&[4]) = 2057;
Language([Dim Currency].[Currency].&[2]) = 2067;


我如何修改我的LINQ以使结果看起来像这样(没有块注释):

   //CALCULATE;
    Language([Dim Currency].[Currency].&[4]) = 2057;
    Language([Dim Currency].[Currency].&[2]) = 2067;

最佳答案

这是Aggregate LINQ运算符的完美用例,因为您要将一个字符串列表(将输入文件拆分为单独的行的结果)转换为单个字符串,该输入文件没有注释块。通常,如果要将列表简化为单个值,或者要将状态从序列的一个元素携带到下一个元素(例如,一个对携带有用的状态,请覆盖)与我们一起使用的是“我们是否在评论区中?”作为布尔值)。

在下面的查询中,我做出了简化的假设,即开始和结束注释将始终位于各自的行上。如果不是这种情况,则Aggregate的主体会变得更复杂,但实际上是相同的(您需要添加代码以处理在“ / *”或“ * /”上的行拆分)。这是满足您需求的查询:

var inComment = false; // start off assuming we're not in a comment
// assume lines is some IEnumerable<string> representing the lines of your file,
// perhaps from a call to File.ReadAllLines(<file name>)
var result =
    lines.Aggregate(new System.Text.StringBuilder(),
                    (builder, line) => {
                         if (!inComment)
                             // more code here if "/*" isn't on its own line
                             inComment = line.StartsWith("/*");

                         if (inComment)
                         {
                             // more code here if "*/" isn't on its own line
                             inComment &= !line.StartsWith("*/");
                             return builder;
                         }

                         if (!inComment) builder.AppendLine(line);

                         return builder;
                     }).ToString();


为了简化示例,我没有在Aggregate方法中包括“我们是否在注释块中”状态,而是在变量Aggregate上关闭了状态。通过将inComment的类型更改为inComment(而不是上面的查询中的Aggregate),并使用Tuple<Boolean StringBuilder>代替StringBuilderItem1,可以消除对inComment的关闭。而不是Item2



编辑:我没有解释builder方法的主体,这可能很有价值,特别是因为其他评论者使用正则表达式链接到SO问题。首先,您不能使用单个正则表达式删除所有注释块,而必须使用正则表达式以及一些其他逻辑。在linked post中,此附加逻辑由Aggregate方法提供。这是比此处所需的解决方案重得多的解决方案。相反,您需要具有两个状态的简单状态机:InComment和NotInComment。当您处于InComment状态时,请检查您所在的注释是否在当前行结束,如果是,则转到NotInComment状态。处于NotInComment状态时,请检查注释是否在当前行开始。如果是这样,则跳过该行并移动InComment状态。如果不是,则将该行添加到输出中。 InComment状态由Regex.Replace块表示,NotInComment状态是其他所有内容。

关于c# - 从文件中删除评论,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22915612/

10-10 07:38