Powershell 中无法确定的返回副作用

问题描述 投票:0回答:1

给出以下输入

$value='Line\"\nString'
$value_type='Interpolated'
.

的片段

注意:

$value
包含文字转义序列,而不是转义字符。

产生以下变量:

  • [string] $value='Line\"\nString'
  • [string] $value3='Line" String'
    空格是换行符。
  • [Object[13]] $value2=['Line"', ..., '"Line"']
  • $value2[0].GetType() = 'System.Text.StringBuilder'
        function _unescape([string] $value, [string] $value_type) {
            function _unescape_core([string] $value) {
                # this should really be part of the dotnet runtime, somewhere...
                # Url decode incorrectly decodes some characters, e.g. % = %25
                # Regex decode does not decode all characters
                $sb = [System.Text.StringBuilder]::new($value.Length)
                $last_is_bs = $false
                for ($pos = 0; $pos -lt $value.Length; $pos += 1) {
                    [char] $c = $value[$pos]
                    if ($last_is_bs) {
                        switch ($c) {
                            'a' { $sb.Append([char]0x07) }
                            'b' { $sb.Append([char]0x08) }
                            't' { $sb.Append([char]0x09) }
                            'n' { $sb.Append([char]0x0a) }
                            'v' { $sb.Append([char]0x0b) }
                            'f' { $sb.Append([char]0x0c) }
                            'r' { $sb.Append([char]0x0d) }
                            'x' {
                                $pos += 2
                                if ($pos -ge $value.Length) {
                                    throw "Invalid escape sequence: \x at end of string"
                                }
                                # hex escape sequence
                                $hex = $value.SubString($sb.Length + 1, 2)
                                $hex = [int]('0x' + $hex)
                                $sb.Append([char]$hex)
                            }
                            'u' {
                                $pos += 4
                                if ($pos -ge $value.Length) {
                                    throw "Invalid escape sequence: \u at end of string"
                                }
                                # unicode escape sequence
                                $hex = $value.SubString($sb.Length + 1, 4)
                                $hex = [int]('0x' + $hex)
                                $sb.Append([char]$hex)
                            }
                            'U' {
                                $pos += 8
                                if ($pos -ge $value.Length) {
                                    throw "Invalid escape sequence: \U at end of string"
                                }
                                # unicode escape sequence
                                $hex = $value.SubString($sb.Length + 1, 8)
                                $hex = [int]('0x' + $hex)
                                # add the surrogate pair
                                $sb.Append([System.Char]::ConvertFromUtf32($hex))
                            }
                            default {
                                $sb.Append($c)
                            }
                        }
                        $last_is_bs = $false
                    }
                    else {
                        if ($c -eq '\') {
                            $last_is_bs = $true
                        }
                        else {
                            $sb.Append($c)
                        }
                    }
                }
                if ($last_is_bs) {
                    throw "Invalid escape sequence: \ at end of string"
                }
                [string] $value3 = $sb.ToString()
                return [string]$value3
            }

            if ($value_type -ne 'Interpolated') {
                return $value
            }
            $value2 = (_unescape_core $value)
            return $value2
        }

对于更小的工作样本,整个 for 循环可以替换为

[char] $c = $value[$pos]
sb.Append($c)

结果不一样,但是很相似

stringbuilders 数组的长度等于返回的字符数。所以第一个是 13,后面的例子是 15。

何时将字符串隐式转换为包含 13 个 StringBuilder 的数组? 如何防止这种转换? 任何人都可以向我解释这种影响吗?我想我要疯了盯着调试器并在谷歌上搜索几个小时。

一些背景知识:我正在尝试将 PowerShell 作为一种语言进行实际学习,并认为这将是一次有趣的学习体验......

在此先感谢您的帮助!

powershell side-effects
1个回答
0
投票

评论中提供了答案,但要关闭它,StringBuilder

类中的所有
append方法返回实例本身,基本上这是允许方法链接,例如:

[System.Text.StringBuilder]::new().
    AppendLine('foo').
    AppendLine('bar').
    AppendLine('baz').
    ToString()

这会在 PowerShell 中产生意想不到的结果,正如您遇到的那样,方法调用的输出成为函数输出的一部分。有关详细信息,请参阅这个优秀的答案

$output = & {
    $sb = [System.Text.StringBuilder]::new()
    $sb.Append('foo')
    $sb.ToString()
}

$output

# Capacity MaxCapacity Length   <= Output from the StringBuilder
# -------- ----------- ------
#       16  2147483647      3
# foo                           <= The actual output we wanted from this Script Block

解决方案是简单地重定向或捕获方法输出,即:

$sb.Append([char]0x07)

应该是:

$sb = $sb.Append([char]0x07)

# or assign to `$null`
$null = $sb.Append([char]0x07)

# or redirect to `$null`
$sb.Append([char]0x07) > $null

# or cast to `void`
[void] $sb.Append([char]0x07)

# or pipe to `Out-Null` (not recommended in Windows PowerShell 5.1)
$sb.Append([char]0x07) | Out-Null
© www.soinside.com 2019 - 2024. All rights reserved.