Powershell 计算多个文件上的注释数,包括多行注释

Powershell 计算多个文件上的注释数,包括多行注释,powershell,Powershell,我正在尝试编写一个脚本,对多个文件中的所有注释进行计数,包括单行(//)和多行(/**/)注释,并打印出总数。因此,下面的文件将返回4 // Foo var text = "hello world"; /* Bar */ alert(text); 需要包括特定的文件类型,并排除某些文件类型和文件夹,我的代码中已经有了这些文件类型和文件夹 我目前的代码是: ( gci -include *.cs,*.aspx,*.js,*.css,*.master,*.html -exclude

我正在尝试编写一个脚本,对多个文件中的所有注释进行计数,包括单行(//)和多行(/**/)注释,并打印出总数。因此,下面的文件将返回4

// Foo

var text = "hello world";

/*
   Bar
*/

alert(text);
需要包括特定的文件类型,并排除某些文件类型和文件夹,我的代码中已经有了这些文件类型和文件夹

我目前的代码是:

(   gci -include *.cs,*.aspx,*.js,*.css,*.master,*.html -exclude *.designer.cs,jquery* -recurse `
    | ? { $_.FullName -inotmatch '\\obj' } `
    | ? { $_.FullName -inotmatch '\\packages' } `
    | ? { $_.FullName -inotmatch '\\release' } `
    | ? { $_.FullName -inotmatch '\\debug' } `
    | ? { $_.FullName -inotmatch '\\plugin-.*' } `
    | select-string "^\s*//" `
).Count
如何更改此选项以获得多行注释

更新:我的最终解决方案(比我要求的略为稳健)如下:

$CodeFiles = Get-ChildItem -include *.cs,*.aspx,*.js,*.css,*.master,*.html -exclude *.designer.cs,jquery* -recurse |
    Where-Object { $_.FullName -notmatch '\\(obj|packages|release|debug|plugin-.*)\\' }

$TotalFiles = $CodeFiles.Count

$IndividualResults = @()

$CommentLines = ($CodeFiles | ForEach-Object{ 
    #Get the comments via regex
    $Comments = ([regex]::matches(
        [IO.File]::ReadAllText($_.FullName), 
        '(?sm)^[ \t]*(//[^\n]*|/[*].*?[*]/)'
    ).Value -split '\r?\n') | Where-Object { $_.length -gt 0 }

    #Get the total lines
    $Total = ($_ | select-string .).Count
    #Add to the results table
    $IndividualResults += @{
        File = $_.FullName | Resolve-Path -Relative; 
        Comments = $Comments.Count;
        Code = ($Total - $Comments.Count)
        Total = $Total
    }
    Write-Output $Comments
}).Count

$TotalLines = ($CodeFiles | select-string .).Count

$TotalResults = New-Object PSObject -Property @{
    Files = $TotalFiles
    Code = $TotalLines - $CommentLines
    Comments = $CommentLines
    Total = $TotalLines
}

Write-Output (Get-Location)
Write-Output $IndividualResults | % { new-object PSObject -Property $_} | Format-Table File,Code,Comments,Total
Write-Output $TotalResults | Format-Table Files,Code,Comments,Total

IMO更好的方法是通过删除单行/多行注释来计算净代码行数

首先,创建一个脚本,该脚本处理单个文件并返回上述sample.cs的结果
5

((Get-Content sample.cs -raw) -replace "(?sm)^\s*\/\/.*?$" `
  -replace "(?sm)\/\*.*?\*\/.*`n" | Measure-Object -Line).Lines
编辑:在不删除空行的情况下,构建与总行的差异

## Q:\Test\2018\10\31\SO_53092258.ps1

$Data = Get-ChildItem *.cs | ForEach-Object {
    $Content = Get-Content $_.FullName -Raw
    $TotalLines = (Measure-Object -Input $Content -Line).Lines
    $CodeLines = ($Content -replace "(?sm)^\s*\/\/.*?$" `
          -replace "(?sm)\/\*.*?\*\/.*`n" | Measure-Object -Line).Lines
    $Comments = $TotalLines - $CodeLines
    [PSCustomObject]@{
        File    = $_.FullName
        Lines   = $TotalLines
        Comments= $Comments
    }
}

$Data
"="*40
"TotalLines={0} TotalCommentLines={1}" -f (
    $Data | Measure-Object -Property Lines,Comments -Sum).Sum
样本输出:

> Q:\Test\2018\10\31\SO_53092258.ps1

File                          Lines Comments
----                          ----- --------
Q:\Test\2018\10\31\example.cs    10        5
Q:\Test\2018\10\31\sample.cs      9        4
============================================
TotalLines=19 TotalCommentLines=9

需要明确的是:使用字符串匹配/正则表达式并不是检测JavaScript/C代码中注释的完全可靠的方法,因为可能存在误报(例如,
var s=“/*hi*/”;
);对于健壮的解析,您需要一个语言解析器

如果这不是一个问题,并且在它们自己的行上检测注释(以空格开头)就足够了,这里有一个简明的解决方案(PSv3+):

对于示例输入,
ForEach对象
命令产生
4

删除
^[\t]*
部分以匹配行中任何位置开始的注释

  • 该解决方案将每个输入文件作为单个字符串读取,然后使用该方法提取所有(可能是跨行)注释

    • 注意:您可以使用
      Get Content-Raw
      将文件作为单个字符串读取,但这要慢得多,尤其是在处理多个文件时

    • 正则表达式使用内联选项
      s
      m
      (?sm)
      )分别使
      匹配换行符,并使锚定
      ^
      $
      分别匹配换行符

    • ^[\t]*
      匹配行首的任何空格和制表符组合(如果有)

    • /[^\n]*$
      匹配从
      /
      开始到行尾的字符串
    • /[*].*?[*]/
      跨多行匹配块注释;请注意惰性量词,
      *?
      ,它确保匹配结束符的下一个实例
  • 然后将匹配的注释(
    .Value
    )拆分为单独的行(
    -split'\r?\n'
    ),并输出

  • 然后对所有文件的结果行进行计数(
    .Count


至于你尝试了什么:

这种方法的基本问题是,带有文件信息对象输入的
Select String
(例如由
Get ChildItem
提供)总是逐行处理输入文件


虽然可以通过在
ForEach对象
脚本块内调用
Select String
来解决这一问题,在脚本块中,您可以将每个文件的内容作为单个字符串传递给
Select String
,但直接使用底层regex.NET类型(如上所示)效率更高。

问题是什么?除了您的代码只计算易于计算的单行注释外,我没有看到获取多行注释的尝试。@LotPings很好,这是我的问题。我不知道如何评估多行注释…顺便说一句,powershell比较运算符的默认值是忽略大小写。由于-match是基于正则表达式的,所以您可以使用一个替代项,而不是几个where->
| where对象全名-notmatch“\\obj| \\ packages | \\ release | \\ debug | \\ plugin-”
,这与我想做的是相反的。我需要的是评论行的数量,不是我知道的非评论行的数量,但有时你会从不同的角度看得更远。请参阅更改后的答案。
(Get-ChildItem -include *.cs,*.aspx,*.js,*.css,*.master,*.html -exclude *.designer.cs,jquery* -recurse |
  Where-Object { $_.FullName -notmatch '\\(obj|packages|release|debug|plugin-.*)' } |
    ForEach-Object { 
      [regex]::matches(
        [IO.File]::ReadAllText($_.FullName), 
        '(?sm)^[ \t]*(//[^\n]*|/[*].*?[*]/)'
      ).Value -split '\r?\n'
    }
 ).Count