powershell - 解析文件以创建行数组
问题描述
这看起来非常简单,但我错过了一些东西。我只需要向数组 [0]、数组 [1] 等添加一个数组。我正在获取一个 vcard 文件并尝试读取一个 vcard 的所有行并将它们放入一个数组中,然后将该数组放入一个数组中所以 array[0] 将是 vcard 1,array[1] 将是下一个,等等。
$c = Get-Content -Path C:\temp\Contacts_Backup.vcf
$counter=0
$contact=@()
$allcontacts=@()
Foreach ($line in $c){
$contact += $line
if ($line -eq 'END:VCARD'){
$allcontacts[$counter++] = $contact
$contact=@()
}
}
结果:无法索引到 System.String 类型的对象。
解决方案
tl;博士:
您不能通过分配给不存在的索引来“增长”数组;如果你从
@()
- 一个空数组开始 - 你必须使用+=
“附加”元素(数组是固定大小的集合,所以真正发生的是每次都必须分配一个新数组,其中包含旧元素,然后是新元素) .+=
因此在循环中使用是低效的,有两种选择:使用 .NET 可扩展列表类型更有效地构建类似数组的集合。
最好 - 因为它更方便和更快 -让PowerShell为您创建数组,只需捕获
foreach
变量 ($array = @(foreach (...) { ... })
)中循环的输出
详情如下。
您的代码确实有问题,尽管它会产生的症状与您当前的问题不同;使用一个简化的例子:
PS> $allcontacts=@(); $allcontacts[0] = 'one', 'two'
Index was outside the bounds of the array. # ERROR
...
也就是说,@()
创建一个空数组,您不能通过访问不存在的index来隐式地“扩展”它。
使用+=
,就像你对你的$contacts
数组所做的那样,确实有效:
$allcontacts=@(); $allcontacts += , ('one', 'two')
请注意使用数组构造运算符,
来确保将 RHS 操作数作为一个整体添加为单个新元素;没有它,将添加多个元素,每个元素一个。
然而,虽然用作品“扩展”了一个数组,但+=
实际上你每次都是在幕后创建一个新数组,因为数组根据定义是固定大小的集合。
对于较大的集合,这可能会成为性能问题,最好使用列表数据类型,例如[System.Collections.Generic.List[object]]
[1]:
$allcontacts = New-Object Collections.Generic.List[object]
$allcontacts.Add(('one', 'two'))
请注意,需要将要添加的数组作为单个列表元素括起来,(...)
以便该.Add()
方法将其识别为单个参数。
退后一步:您可以让PowerShell通过简单地捕获整个命令的输出来收集$contact
整个数组中的子数组$allcontacts
foreach
:
$c = Get-Content -Path C:\temp\Contacts_Backup.vcf
$contact=@()
$allcontacts = @(foreach ($line in $c){
$contact += $line
if ($line -eq 'END:VCARD'){
# Output the $contact array as a *single* object,
# using ",", the array-construction operator
, $contact
# Reset for the next contact.
$contact=@()
}
})
$allcontacts
最终将成为一个常规的 PowerShell 数组,类型为[object[]]
. @(...)
仅当您需要确保它$allcontacts
是一个数组(即使*.vcf
文件仅包含一个联系人定义)时,才需要使用数组子表达式运算符 ( )。
[1] 一个非通用的替代方法是[System.Collections.ArrayList]
,但它的缺点是它的.Add()
方法返回一个 value,要求您使用例如抑制该值,$null = $arrayList.Add(...)
以免污染 PowerShell 的输出流。
推荐阅读
- javascript - 如何仅在 H3 中获取 hexRing() 的外边缘的顶点?
- html - 如何让这个侧边栏出现在右边而不是左边?
- javascript - 在 ElasticSearch 中为文档字段赋予不同的优先级
- android-room - 尝试从分页 3 寻呼机内的房间获取寻呼源时出现“无法访问主线程上的数据库”错误
- java - 更改存储在不同线程上的列表中的对象的字段
- c# - 如何在 ConfigureServices 中创建依赖于数据库上下文的实例
- google-cloud-platform - 谷歌文档人工智能
- python - python的VSCode自动完成字符串参数
- python - 无法使用 python selenium 单击电子邮件验证按钮
- android - android.util.AndroidRuntimeException:从 Activity 标志外调用 startActivity()