我正在尝试编写一个脚本,该脚本计算多个文件中的所有注释,包括单行(//)和多行(/ * * /)注释并打印出总数。因此,以下文件将返回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
答案 0 :(得分:2)
要清楚:使用字符串匹配/正则表达式并不是检测JavaScript / C#代码中注释的完全可靠的方法,因为可能存在误报(例如var s = "/* hi */";
);为了进行可靠的解析,您需要一个语言解析器。
如果这无关紧要,并且足以在其行上检测注释(以开头开始),并且可以选择以空格开头,那么这是一种简洁的解决方案(PSv3 +):
(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
使用示例输入,ForEach-Object
命令产生4
。
删除^[ \t]*
部分以匹配一行开始的注释。
该解决方案使用[IO.File]::ReadAllText()
作为一个字符串读取每个输入文件,然后使用[regex]::Matches()
方法提取所有(可能跨行)注释。
注意:您可以使用Get-Content -Raw
代替单个字符串读取文件,但这要慢得多,尤其是在处理多个文件时。
正则表达式使用内联选项s
和m
((?sm)
)分别使.
也匹配换行符并锚定{{1} }和^
分别匹配。
$
匹配行开头的空格和制表符的任何组合。
^[ \t]*
与以//[^\n]*$
开头的字符串匹配到该行的末尾。//
在多行中匹配一个块注释;请注意 lazy 量词/[*].*?[*]/
,它确保结束*?
分隔符的 next 实例非常匹配。然后将匹配的注释(*/
)分成几行(.Value
),并输出。
然后计算所有文件中的结果行(-split '\r?\n'
)
关于您尝试过的事情:
您的方法的基本问题是,.Count
带有文件信息对象输入(例如Select-String
提供)始终不变地逐行处理输入文件 。< / p>
尽管可以通过在Get-ChildItem
脚本块中调用Select-String
来解决此问题,在该脚本块中,您将每个文件的内容作为单个字符串传递给ForEach-Object
,直接如上所示,使用底层正则表达式.NET类型更为有效。
答案 1 :(得分:0)
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