繁体   English   中英

为什么 + 运算符在 powershell 中添加空格

[英]Why + operator adding space in powershell

我遇到奇怪的问题。 我有一个文件,内容如下

-----MyData-----
aaa
bbb
ccc
ddd
-----YourData-----

我写了一个 function 来在一个字符串中获取文件的所有数据,除了第一行和最后一行。 function如下

function readFile([string] $datapath){
$returningData = $null
foreach($line in [System.IO.File]::ReadLines($datapath)) {
    if(-not ($line -like '*-MyData-*') -and -not ($line -like '*-YourData-*')){
        $returningData+=$line
    }
}
return $returningData
}

现在,此方法按预期返回“ aaabbbcccddd ”,但在 IF 块中,如果我使用 $returningData+$line 而不是我现在使用的 write 那么它返回“ aaa bbb ccc ddd ”。

我寻找它,但找不到任何答案。 为什么简单的串联添加一个额外的空间?

这里有两件事在起作用:

显示数据

PowerShell 将对象(包括数组)显示和/或转换为字符串的方式:

$MyData = 'aaa', 'bbb', 'ccc', 'ddd'

PS C:\> "$MyData"
aaa bbb ccc ddd

PS C:\> Write-Host $MyData
aaa bbb ccc ddd

或来自管道的 output(展开):

PS C:\> $MyData # Simular to: $MyData | ForEach-Object { $_ }
aaa
bbb
ccc
ddd

另请注意,arrays 在字符串或 output 中被展平(参见例如:为什么 PowerShell 会自动展平 ZA3DCBC53F9D0CE672FE71?

为了更好地显示 object 及其结构,您可以考虑使用序列化程序,例如ConvertTo-Json

PS C:\> ConvertTo-Json $MyData
[
  "aaa",
  "bbb",
  "ccc",
  "ddd"
]

ConvertTo-Expression用于更复杂的对象,例如:

$MyObject = 'aaa', @([datetime]'1963-10-07', [version]'1.2.3'), 'bbb'

PS C:\> Write-Host $MyObject
aaa 10/7/1963 12:00:00 AM 1.2.3 bbb

PS C:\> ConvertTo-Expression $MyObject
'aaa',
(
        [datetime]'1963-10-07T00:00:00.0000000',
        [version]'1.2.3'
),
'bbb'

类型铸造

这里发挥的另一件事是自动类型转换,其中对象在用作运算符的操作数时被隐式转换为相同的类型。 这意味着如果操作数的类型不同,则第一个操作数的类型将用于操作,第二个操作数将转换为与第一个操作数相同的类型(如果可能)。

这对比较运算符很重要:

PS C:\> 10 -gt '9' # 10 > 9
True

PS C:\> '10' -gt 9 # '10' < '9'
False

和大多数其他运算符,包括算术运算符

PS C:\> 10 + '9' # Results in a integer: 10 + 9
19

PS C:\> '10' + 9 # Results in a string: '10' + '9'
109

而且在数组的情况下

PS C:\> 'aaa' + 'bbb', 'ccc' # Results in a string: 'aaa' + 'bbb ccc'
aaabbb ccc

PS C:\> 'aaa', 'bbb' + 'ccc' # Results in an array: 'aaa', 'bbb' + @('ccc')
aaa
bbb
ccc

如果第一个操作数是$Null (它不是任何数据类型的一部分),则使用第二个操作数的类型:

PS C:\> $a = $Null + 'aaa'
PS C:\> $a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

PS C:\> $a = $Null + @('aaa')
PS C:\> $a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

结论

改变你的线路:

$returningData = $null

至:

$returningData = @()

或者:

$returningData = ''

在这件事上可能会给你不同的结果。

注意:使用增加赋值运算符 ( += ) 创建 object 集合一样,您通常应该避免使用增加赋值运算符 ( += ) 来构建字符串,因为它是指数级的昂贵。

相反,我建议您使用管道和-Join运算符来构建字符串:

PS C:\> $MyData -Join ''
aaabbbcccddd

或在您的脚本中:

$returningData = @(
    foreach($line in $MyData) {
        if(-not ($line -like '*a*') -and -not ($line -like '*b*')){ $line }
    }
) -Join ''

@iron 的答案有很多很好的信息,但我们不要忽视 PowerShell 的简洁程度。 我设法将其简化为几行:

$File = 'C:\temp\MyData.txt'
$Patterns = @('.-MyData-.','.-YourData-.','^$')
$String = (Select-String -Pattern $Patterns -Path $File -NotMatch ).line -join ''

假设用例与问题所示的一样简单。

我还要指出,如果其他评论是正确的并且某处有胭脂空间。 你可以 pipe 这个到ForEach-Object来修剪每一行。

$File = 'C:\temp\MyData.txt'
$Patterns = @('.-MyData-.','.-YourData-.','^$')
$String = ( (Select-String -Pattern $Patterns -Path $File -NotMatch ).line | ForEach-Object{ $_.Trim() } ) -join ''

.Trim()只会在行首和行尾占用空格。 如果要删除每行的所有空格,可以按照评论之一的建议使用.Replace( ' ', '' )

我敢肯定我的 RegEx 可能会好一点,但我得走了,如果有人有一些指示,请编辑或添加到评论中。 谢谢。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM