6

这是一个技术问题,但作为一个练习,我的目的是编写一个 PS 来接受管道输入,并使用正则表达式作为参数,并突出显示与正则表达式匹配的任何文本。

我找不到任何信息的部分是它很容易匹配文本、捕获到缓冲区或替换文本。但是我需要用颜色控制替换匹配的文本,原始文本,然后恢复以前的颜色。除了使用写入输出之外,我似乎找不到任何生成颜色输出的方法,并且不能在一次写入中执行单独的颜色,这意味着:

- 匹配正则表达式

-write-host 在默认颜色匹配之前输出所有文本,使用 -NoNewLine

-write-host 匹配,使用 -NoNewLine

-write-host 剩下的

这看起来很混乱,如果我们想要支持多个匹配,就会变得更加混乱。有没有更雄辩的方法来做到这一点?

4

3 回答 3

6

Write-Host是这样做的正确方法。使用结果对象的.Index.Length属性Match来确定匹配文本的确切位置。您只需要小心跟踪索引:)

这适用于多场比赛,并且不是非常不整洁的 IMO:

function ColorMatch
{
   param(
      [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
      [string] $InputObject,

      [Parameter(Mandatory = $true, Position = 0)]
      [string] $Pattern
   )

   begin{ $r = [regex]$Pattern }
   process
   {
       $ms = $r.Matches($inputObject)
       $startIndex = 0

       foreach($m in $ms)
       {
          $nonMatchLength = $m.Index - $startIndex
          Write-Host $inputObject.Substring($startIndex, $nonMatchLength) -NoNew
          Write-Host $m.Value -Back DarkRed -NoNew
          $startIndex = $m.Index + $m.Length
       }

       if($startIndex -lt $inputObject.Length)
       {
          Write-Host $inputObject.Substring($startIndex) -NoNew
       }

       Write-Host
   }
}
于 2012-09-26T20:54:40.443 回答
1

或者,我发现使用ANSI/VT100 格式更简单,并且使用更大范围的颜色完全符合我的需要:

$esc=[char]27
$fileContents="abc455315testing123455315abc"
$keywordSearch="testing123"

$fileContents -replace $keywordSearch,"$esc[38;2;0;200;255m$keywordSearch$esc[0m"

请注意,这仅适用于 PowerShell 控制台窗口,不适用于 PowerShell ISE。这个维基百科页面也很有帮助;特别是关于选择颜色的这一行:

ESC[ 38;2;⟨r⟩;⟨g⟩;⟨b⟩ m 选择 RGB 前景色

于 2019-10-10T03:35:52.267 回答
1

这是拉特金答案的延伸。在这里,我扩展了 Match 对象,以便可以更轻松地为此目的以及其他目的对其进行处理。

function Split-Match {
    param([Parameter(Mandatory = $true)]
    $match
    )
    $sections = @()
    $start = 0
    $text = $m.Line
    foreach ($m in $match.Matches) {
        $i = $m.Index
        $l = $m.Length

        $sections += $false, $text.Substring($start, $i - $start)
        $sections += $true, $text.Substring($i, $l)
        $start = $i + $l
    }
    $sections += $false, $text.Substring($start)
    $match | Add-Member -Force Sections $sections
    $match
}

function Write-Match {
    param([Parameter(Mandatory = $true)]
    $match
    )
    $fg = "White"
    $bg = "Black"
    foreach($s in $match.Sections) {
        if ($s.GetType() -eq [bool]) {
            if ($s) {
                $fg = "White"
                $bg = "Red"
            } else {
                $fg = "White"
                $bg = "Black"
            }
        } else {
            Write-Host -NoNewline -ForegroundColor $fg -BackgroundColor $bg $s
        }
    }
    Write-Host
}

$string = @'
Match this A
Not this B
Not this C
But this A
'@
$m = $string | select-string -CaseSensitive -AllMatches "A"
$m = Split-Match $m
Write-Match $m

输出

于 2019-03-29T15:24:13.210 回答