解析文件以创建行数组 [英] Parsing a file to create an array of lines

查看:63
本文介绍了解析文件以创建行数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这看起来非常简单,但我遗漏了一些东西.我只需要向数组[0]、数组[1]等添加一个数组.我正在获取一个 vcard 文件并尝试读取一个 vcard 的所有行并将它们放入一个数组中,然后将该数组放入一个数组中,这样数组 [0] 将是 vcard 1,数组 [1] 将是下一个,等等.

This seems so incredibly simple but I am missing something. I just need to add an array to array[0], array[1], etc. I am taking a vcard file and trying to read all the lines of one vcard and put them in an array and then place that array in an array so array[0] will be vcard 1, array[1] will be the next, etc.

$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 类型的对象.

Result: Unable to index into an object of type System.String.

推荐答案

tl;dr:

  • 你不能通过分配给一个不存在的索引来增长"一个数组;如果你以 @() 开头 - 一个空数组 - 你必须使用 += 来追加"元素(数组是固定大小的集合,所以真正发生的是每次都必须分配一个数组,其中包含旧元素,然后是新元素).

  • You cannot "grow" an array by assigning to a nonexistent index; if you start with @() - an empty array - you must use += to "append" elements (arrays are fixed-size collections, so what really happens is that a new array must be allocated every time that contains the old elements followed by the new one).

因此在循环中使用 += 效率低下,并且有两种替代方法:

  • 使用 .NET 可扩展列表类型更有效地构建类似数组的集合.

  • Use a .NET extensible list type to build an array-like collection more efficiently.

最好 - 因为它既方便又快捷 - PowerShell 为您创建数组,只需从 foreach 捕获输出在变量中循环
($array = @(foreach (...) { ... }))

Preferably - because it is both more convenient and faster - let PowerShell create the array for you, simply by capturing the output from a foreach loop in a variable
($array = @(foreach (...) { ... }))

详情如下.

您的代码确实有问题,尽管它产生的症状与您的问题当前陈述的不同;使用一个简化的例子:

Your code indeed has a problem, though the symptom it would produce differs from what your question currently states; using a simplified example:

PS> $allcontacts=@(); $allcontacts[0] = 'one', 'two'
Index was outside the bounds of the array.  # ERROR
...

也就是说,@() 创建一个 数组,你不能通过访问一个不存在的索引来隐式地扩展"它.

That is, @() creates an empty array, which you cannot implicitly "extend" by accessing a non-existent index.

使用 +=,就像使用 $contacts 数组一样,确实有效:

Using +=, as you do with your $contacts array, does work:

$allcontacts=@(); $allcontacts += , ('one', 'two')

注意数组构造运算符,的使用,以确保RHS操作数作为一个整体添加为一个单个新元素;没有它,将添加多个元素,每个元素一个.

Note the use of array-construction operator , to ensure that the RHS operand is added as a whole as a single new element; without it, multiple elements would be added, one for each element.

然而,虽然使用 += 来扩展"一个数组是有效的,但实际上你每次都在幕后创建一个 数组,因为数组是根据定义固定大小集合.

However, while "extending" an array with += works, in reality you're creating a new array behind the scenes every time, because arrays are by definition fixed-size collections.

对于较大的集合,这可能会成为性能问题,最好使用 list 数据类型代替,例如 [System.Collections.Generic.List[object]][1]:

With larger collections, this can become a performance issue, and it is better to use a list data type instead, such as [System.Collections.Generic.List[object]][1]:

$allcontacts = New-Object Collections.Generic.List[object]
$allcontacts.Add(('one', 'two'))

注意需要将要添加的数组 - 作为单个列表元素 - 在 (...) 中,以便 .Add() 方法将其识别为一个参数.

Note the need to enclose the array to add - as a single list element - in (...) so that the .Add() method recognizes it as a single argument.

退一步:您可以让 PowerShell 收集整个 $allcontacts 数组中的 $contact 子数组简单地捕获整个 foreach 命令的输出:

Taking a step back: You can let PowerShell collect the $contact sub-arrays in the overall $allcontacts array by simply capturing the output from the entire foreach command:

$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 文件仅包含 一个 联系人定义.

$allcontacts will end up as a regular PowerShell array, typed [object[]]. Use of the array-subexpression operator (@(...)) is only necessary if you need to ensure that $allcontacts is an array even if the *.vcf file contains only one contact definition.

[1] 一个非通用的替代方案是 [System.Collections.ArrayList],但它的缺点是它的 .Add() 方法 返回一个值,要求您使用例如 $null = $arrayList.Add(...) 来抑制该值,以免污染 PowerShell 的输出流.

[1] A non-generic alternative is [System.Collections.ArrayList], but its downside is that its .Add() method returns a value, requiring you to suppress that value with, e.g., $null = $arrayList.Add(...) so as not to pollute PowerShell's output stream.

这篇关于解析文件以创建行数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆