给出以下输入
$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 作为一种语言进行实际学习,并认为这将是一次有趣的学习体验......
在此先感谢您的帮助!
评论中提供了答案,但要关闭它,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