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