Используйте Powershell, чтобы распечатать номер строки кода, соответствующего RegEx - PullRequest
5 голосов
/ 09 июня 2009

Я думаю, что в нашем источнике есть куча закомментированного кода, и вместо того, чтобы немедленно его удалить, мы просто оставили его Теперь я хотел бы провести уборку.

Если предположить, что у меня достаточно хорошего RegEx для поиска комментариев (ниже приведен простой RegEx, и я могу расширить его на основе наших стандартов кодирования), как мне взять результаты файла, который я прочитал, и вывести следующее:

  • Filename
  • Номер строки
  • Фактическая строка кода

Я думаю, что у меня есть основание для ответа здесь, но я не знаю, как взять файл, который я прочитал и проанализировал с помощью RegEx, и выложить его в этом формате.

Я не ищу идеального решения - я просто хочу найти большие блоки закомментированного кода. Посмотрев на результат и увидев группу файлов с одинаковыми именами и порядковыми номерами строк, я смогу сделать это.

$Location = "c:\codeishere"

[regex]$Regex = "//.*;" #simple example - Will expand on this...

$Files = get-ChildItem $Location -include *cs -recurse
foreach ($File in $Files) {
    $contents = get-Content $File
    $Regex.Matches($contents) | WHAT GOES HERE?
}

Ответы [ 4 ]

14 голосов
/ 10 июня 2009

Вы можете сделать:

dir c:\codeishere -filter *.cs -recurse | select-string -Pattern '//.*;' | select Line,LineNumber,Filename
2 голосов
/ 10 июня 2009

Я бы пошел еще дальше. Я хотел бы рассчитать количество последовательных следующих строк. Затем напечатайте имя файла, количество строк и сами строки. Вы можете отсортировать результат по количеству строк (кандидатов на удаление?). Обратите внимание, что мой код не считается с пустыми строками между закомментированными строками, поэтому эта часть рассматривается как два блока закомментированного кода:

// int a = 10;
// int b = 20;

// DoSomething()
// SomethingAgain()

Вот мой код.

$Location = "c:\codeishere"

$occurences = get-ChildItem $Location *cs -recurse | select-string '//.*;'
$grouped = $occurences | group FileName

function Compute([Microsoft.PowerShell.Commands.MatchInfo[]]$lines) {
  $local:lastLineNum = $null
  $local:lastLine = $null
  $local:blocks = @()
  $local:newBlock = $null
  $lines | 
    % { 
      if (!$lastLineNum) {                             # first line
        $lastLineNum = -2                              # some number so that the following if is $true (-2 and lower)
      }

      if ($_.LineNumber - $lastLineNum -gt 1) {        #new block of commented code
        if ($newBlock) { $blocks += $newBlock }
        $newBlock = $null
      }
      else {                                           # two consecutive lines of commented code
        if (!$newBlock) { 
          $newBlock = '' | select File,StartLine,CountOfLines,Lines
          $newBlock.File, $newBlock.StartLine, $newBlock.CountOfLines, $newBlock.Lines = $_.Filename,($_.LineNumber-1),2, @($lastLine,$_.Line)
        }
        else {
          $newBlock.CountOfLines += 1
          $newBlock.Lines += $_.Line
        }
      }
      $lastLineNum=$_.LineNumber
      $lastLine = $_.Line
    }

  if ($newBlock) { $blocks += $newBlock }
  $blocks
}

# foreach GroupInfo objects from group cmdlet
# get Group collection and compute 
$result = $grouped | % { Compute $_.Group }

#how to print
$result | % {
  write-host "`nFile $($_.File), line $($_.StartLine), count of lines: $($_.CountOfLines)" -foreground Green
  $_.Lines | % { write-host $_ }
}

# you may sort it by count of lines:
$result2 = $result | sort CountOfLines -desc
$result2 | % {
  write-host "`nFile $($_.File), line $($_.StartLine), count of lines: $($_.CountOfLines)" -foreground Green
  $_.Lines | % { write-host $_ }
}

Если у вас есть идеи, как улучшить код, опубликуйте его! У меня такое ощущение, что я мог бы сделать это, используя некоторые стандартные командлеты, и код мог бы быть короче ..

2 голосов
/ 10 июня 2009
gci c:\codeishere *.cs -r | select-string "//.*;"

Командлет select-string уже выполняет именно то, что вы запрашиваете, хотя отображаемое имя файла является относительным путем.

1 голос
/ 09 июня 2009

Я бы посмотрел на что-то вроде:

dir $location -inc *.cs -rec | `
  %{ $file = $_; $n = 0; get-content $_ } | `
  %{ $_.FileName = $file; $_.Line = ++$n; $_ } | `
  ?{ $_ -match $regex } | `
  %{ "{0}:{1}: {2}" -f ($_.FileName, $_.Line, $_)}

т.е. добавьте в строку дополнительные свойства, чтобы указать имя файла и номер строки, которые могут передаваться по конвейеру после совпадения с регулярным выражением.

(Использование блоков скриптов -begin / -end ForEach-Object должно упростить это.)

...