Подсчет количества комментариев к нескольким файлам, включая многострочные комментарии - PullRequest
0 голосов
/ 01 ноября 2018

Я пытаюсь написать скрипт, который подсчитывает все комментарии в нескольких файлах, включая как однострочные (//), так и многострочные (/ * * /) комментарии, и выводит итоги. Итак, следующий файл вернет 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

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Чтобы быть ясным: использование соответствия строк / регулярных выражений не является полностью надежным способом обнаружения комментариев в коде 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)), чтобы соответственно сделать . совпадением с символами новой строки и чтобы якоря ^ и $ соответствовали строке отдельно.

    • ^[ \t]* соответствует любому сочетанию пробелов и табуляций, если они есть, в начале строки.

    • //[^\n]*$ соответствует строке, которая начинается с // до конца строки.
    • /[*].*?[*]/ соответствует комментарию блока в нескольких строках; обратите внимание на квантификатор lazy , *?, который обеспечивает совпадение самого следующего экземпляра закрывающего разделителя */.
  • Соответствующие комментарии (.Value) затем разделяются на отдельные строки (-split '\r?\n'), которые выводятся.

  • Затем подсчитываются полученные строки во всех файлах (.Count)


Что касается того, что вы пытались:

Основная проблема вашего подхода заключается в том, что Select-String при вводе данных файла-информации (например, предоставляемых Get-ChildItem) неизменно обрабатывает входные файлы построчно .

Хотя это можно исправить, вызвав Select-String внутри блока сценариев ForEach-Object, в котором вы передаете содержимое каждого файла в виде одной строки в Select-String, непосредственное использование базового регулярного выражения .NET Типы, как показано выше, более эффективны.

0 голосов
/ 01 ноября 2018

Лучшим подходом 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...