Powershell 如何向StringBuilder对象插入颜色线

Powershell 如何向StringBuilder对象插入颜色线,powershell,colors,stringbuilder,Powershell,Colors,Stringbuilder,是否可以向StringBuilder对象添加带颜色的行? 我知道如何使用Write Host添加颜色: Write-Host "Line without a color" Write-Host "Line with red color" -ForegroundColor Red 但不能使用StringBuilder: $sb = New-Object -TypeName "System.Text.StringBuilder" $sb.AppendLine("Line without a col

是否可以向
StringBuilder
对象添加带颜色的行?
我知道如何使用Write Host添加颜色:

Write-Host "Line without a color"
Write-Host "Line with red color" -ForegroundColor Red
但不能使用
StringBuilder

$sb = New-Object -TypeName "System.Text.StringBuilder"
$sb.AppendLine("Line without a color") | Out-Null
$sb.AppendLine("Line with red color") | Out-Null
$sb.ToString()
我更喜欢把所有的行都收集在一起,然后全部打印出来。
StringBuilder
是一种很好的方法,但我也希望一些带有颜色的行。
可能吗

这是我想通过
StringBuilder
获得的输出:


我读了一些关于RTFString builder的文章,但它并没有像预期的那样对我有效

解决方法:

$sb = New-Object -TypeName "System.Text.StringBuilder"
$sb.AppendLine("Line without a color") | Out-Null
$sb.AppendLine("#color:red#Line with red color") | Out-Null


$delim =@([Environment]::NewLine, "\n")
$sbLines = $sb.ToString().Split($delim, [System.StringSplitOptions]::None)
foreach($line in $sbLines){


    if($line.StartsWith("#color:red#")){
        Write-Host $line.Split("#")[2] -ForegroundColor Red
    }
    else{
        Write-Host $line
    }
}
更通用的解决方案:

<#
.SYNOPSIS
A wrapper around Write-Host that supports selective coloring of
substrings via embedded coloring specifications.

.DESCRIPTION
In addition to accepting a default foreground and background color,
you can embed one or more color specifications in the string to write,
using the following syntax:
#<fgcolor>[:<bgcolor>]#<text>#

<fgcolor> and <bgcolor> must be valid [ConsoleColor] values, such as 'green' or 'white' (case does not matter).
Everything following the color specification up to the next '#', or impliclitly to the end of the string,
is written in that color.

Note that nesting of color specifications is not supported.
As a corollary, any token that immediately follows a color specification is treated
as text to write, even if it happens to be a technically valid color spec too.
This allows you to use, e.g., 'The next word is #green#green#.', without fear
of having the second '#green' be interpreted as a color specification as well.

.PARAMETER ForegroundColor
Specifies the default text color for all text portions
for which no embedded foreground color is specified.

.PARAMETER BackgroundColor
Specifies the default background color for all text portions
for which no embedded background color is specified.

.PARAMETER NoNewline
Output the specified string withpout a trailing newline.

.NOTES
While this function is convenient, it will be slow with many embedded colors, because,
behind the scenes, Write-Host must be called for every colored span.

.EXAMPLE
Write-HostColored "#green#Green foreground.# Default colors. #blue:white#Blue on white."

.EXAMPLE
'#black#Black on white (by default).#Blue# Blue on white.' | Write-HostColored -BackgroundColor White

#>
function Write-HostColored() {
    [CmdletBinding()]
    param(
        [parameter(Position=0, ValueFromPipeline=$true)]
        [string[]] $Text
        ,
        [switch] $NoNewline
        ,
        [ConsoleColor] $BackgroundColor = $host.UI.RawUI.BackgroundColor
        ,
        [ConsoleColor] $ForegroundColor = $host.UI.RawUI.ForegroundColor
    )

    begin {
        # If text was given as a parameter value, it'll be an array.
        # Like Write-Host, we flatten the array into a single string
        # using simple string interpolation (which defaults to separating elements with a space,
        # which can be changed by setting $OFS).
        if ($Text -ne $null) {
            $Text = "$Text"
        }
    }

    process {
        if ($Text) {

            # Start with the foreground and background color specified via
            # -ForegroundColor / -BackgroundColor, or the current defaults.
            $curFgColor = $ForegroundColor
            $curBgColor = $BackgroundColor

            # Split message into tokens by '#'.
            # A token between to '#' instances is either the name of a color or text to write (in the color set by the previous token).
            $tokens = $Text.split("#")

            # Iterate over tokens.
            $prevWasColorSpec = $false
            foreach($token in $tokens) {

                if (-not $prevWasColorSpec -and $token -match '^([a-z]*)(:([a-z]+))?$') { # a potential color spec.
                    # If a token is a color spec, set the color for the next token to write.
                    # Color spec can be a foreground color only (e.g., 'green'), or a foreground-background color pair (e.g., 'green:white'), or just a background color (e.g., ':white')
                    try {
                        $curFgColor = [ConsoleColor] $matches[1]
                        $prevWasColorSpec = $true
                    } catch {}
                    if ($matches[3]) {
                        try {
                            $curBgColor = [ConsoleColor] $matches[3]
                            $prevWasColorSpec = $true
                        } catch {}
                    }
                    if ($prevWasColorSpec) {
                        continue
                    }
                }

                $prevWasColorSpec = $false

                if ($token) {
                    # A text token: write with (with no trailing line break).
                    # !! In the ISE - as opposed to a regular PowerShell console window,
                    # !! $host.UI.RawUI.ForegroundColor and $host.UI.RawUI.ForegroundColor inexcplicably
                    # !! report value -1, which causes an error when passed to Write-Host.
                    # !! Thus, we only specify the -ForegroundColor and -BackgroundColor parameters
                    # !! for values other than -1.
                    # !! Similarly, PowerShell Core terminal windows on *Unix* report -1 too.
                    $argsHash = @{}
                    if ([int] $curFgColor -ne -1) { $argsHash += @{ 'ForegroundColor' = $curFgColor } }
                    if ([int] $curBgColor -ne -1) { $argsHash += @{ 'BackgroundColor' = $curBgColor } }
                    Write-Host -NoNewline @argsHash $token
                }

                # Revert to default colors.
                $curFgColor = $ForegroundColor
                $curBgColor = $BackgroundColor

            }
        }
        # Terminate with a newline, unless suppressed
        if (-not $NoNewLine) { write-host }
    }
}


# MAIN
$sb = New-Object -TypeName "System.Text.StringBuilder"
$sb.AppendLine("Line without a color") | Out-Null
$sb.AppendLine("#red#Line with red color") | Out-Null

$delim =@([Environment]::NewLine, "\n")
$sbLines = $sb.ToString().Split($delim, [System.StringSplitOptions]::None)
foreach($line in $sbLines){
    Write-HostColored $line
}

函数Write-HostColored(){
[CmdletBinding()]
param(
[参数(位置=0,ValueFromPipeline=$true)]
[string[]]$Text
,
[开关]$NoNewline
,
[ConsoleColor]$BackgroundColor=$host.UI.RawUI.BackgroundColor
,
[ConsoleColor]$ForegroundColor=$host.UI.RawUI.ForegroundColor
)
开始{
#如果文本作为参数值给出,它将是一个数组。
#与写主机一样,我们将数组展平为单个字符串
#使用简单的字符串插值(默认为用空格分隔元素,
#可通过设置$OFS)进行更改。
如果($Text-ne$null){
$Text=“$Text”
}
}
过程{
如果($Text){
#从通过指定的前景色和背景色开始
#-ForegroundColor/-BackgroundColor,或当前默认值。
$curFgColor=$ForegroundColor
$curBgColor=$BackgroundColor
#按“#”将消息拆分为令牌。
#到“#”实例之间的标记是要写入的颜色或文本的名称(使用上一个标记设置的颜色)。
$tokens=$Text.split(#)
#迭代标记。
$prevWasColorSpec=$false
foreach($tokens中的token){
如果(-not$prevWasColorSpec-和$token-match'^([a-z]*)(:([a-z]+)?$){{一个潜在的颜色规范。
#如果标记是颜色规范,请设置下一个要写入的标记的颜色。
#颜色规格只能是前景色(如“绿色”),也可以是前景色-背景色对(如“绿色:白色”),也可以只是背景色(如“绿色:白色”)
试一试{
$curFgColor=[ConsoleColor]$matches[1]
$prevWasColorSpec=$true
}捕获{}
如果($matches[3]){
试一试{
$curBgColor=[ConsoleColor]$matches[3]
$prevWasColorSpec=$true
}捕获{}
}
如果($prevWasColorSpec){
持续
}
}
$prevWasColorSpec=$false
如果($token){
#一个文本标记:write with(不带尾随换行符)。
#!!在ISE中-与常规PowerShell控制台窗口不同,
#!!$host.UI.RawUI.ForegroundColor和$host.UI.RawUI.ForegroundColor不可分割
#!!报告值-1,当传递给写入主机时会导致错误。
#!!因此,我们仅指定-ForegroundColor和-BackgroundColor参数
#!!对于-1以外的值。
#!!同样,PowerShell Core terminal windows on*Unix*报告也为-1。
$argsHash=@{}
如果([int]$curFgColor-ne-1){$argsHash+=@{'ForegroundColor'=$curFgColor}}
如果([int]$courbgcolor-ne-1){$argsHash+=@{'BackgroundColor'=$courbgcolor}}
写入主机-NoNewline@argsHash$token
}
#恢复为默认颜色。
$curFgColor=$ForegroundColor
$curBgColor=$BackgroundColor
}
}
#除非被抑制,否则以换行符终止
if(-not$NoNewLine){write host}
}
}
#主要
$sb=新对象-类型名称“System.Text.StringBuilder”
$sb.AppendLine(“没有颜色的线”)|输出空值
$sb.AppendLine(#红色#带红色的线条)|输出空值
$delim=@([Environment]::换行符,“\n”)
$sbLines=$sb.ToString().Split($delim,[System.StringSplitOptions]::无)
foreach($sbline中的行){
写$line
}

StringBuilder
对象没有颜色的概念。如果你想要颜色,你需要在字符串中嵌入转义码,并以你想要的颜色输出字符串。@Bill\u Stewart你有一个小例子如何使用这种东西吗?我发现了一些在字符串上打印颜色的函数:但是可能有一些默认代码,比如?比如“{color:#8B0000}这是一条红线”,你必须自己写。在代码的显示部分,您需要查找嵌入的颜色和输出。没有什么内置的东西可以帮你做到这一点。颜色是“仅输出”功能。