2

全部!

我正在编写将标准 INI 文件结构转换为基于哈希表和数组的代码。例如,如下所示的 INI 片段:

[Book]
title="Moby Dick"
author="Herman Melville"
genre=fiction
genre=fantasy

[Book]
title="James and the Giant Peach"
author="Roald Dahl"
genre="fiction"

看起来像:

@{
    "Book" = [
        @{
            "title" = ["Moby Dick"];
            "author" = ["Herman Melville"];
            "genre" = ["fiction","fantasy"]
        },
        @{
            "title" = ["James and the Giant Peach"];
            "author" = ["Roald Dahl"];
            "genre" = ["fiction"]
        }
    ]

}

我想考虑具有多个同名部分和具有多个同名属性的部分的 INI 文件,因此是这种数据结构。我知道我可以使用一棵树来做同样的事情,但我不太关心它的速度,而且在我编写它的时候这更容易实现。

这是通过更新一个哈希表来完成的,该哈希表将一个部分中的所有属性与其值相关联(我们称之为它$items),然后更新将每个部分与上述哈希表相关联的主哈希表(我们称之为这个$results)。散列表是全局的,属性散列表在迭代到新部分时被清除。

虽然我编写的代码可以做到这一点并且运行良好,但几分钟后我对 Powershell 清除哈希表的方式感到困惑。如果我清除$itemsusing $items.Clear()则与所有元素关联的哈希表$results也会被清除。但是,如果我通过声明“清除”它,则不会发生这种情况$items=@{}

我假设发生这种情况是因为前一种情况下的哈希表都是对全局哈希表的引用,并且在后者中是独立的对象。这是怎么回事?

代码如下;抱歉,如果其中任何一个令人困惑(并且它不是典型的 Powershell 语法)。替换$items = @{}$items = $items.Clear()复制:

function parse ($file) {
    $result = @{}
    if (!(Test-Path $file)) {   
        write-host "File does not exist: $file"
    } elseif (!($data = cat $file)) {
        write-host "File has no data: $file"
    } else {
        $last_value = ""
        $last_data = ""
        $items = @{}
        foreach ($line_raw in $data | ?{$_.Trim().Length -gt 0}) {
            $line = $line_raw.TrimStart().TrimEnd()
            $first_char = $line[0]
            switch ($first_char) {
                ';' { 
                    continue 
                }
                '[' {
                    $key = $line -replace "\[|\]",""
                    if ($last_key) {
                        if (!($result.ContainsKey($last_key)))
                            { $result.Add($last_key,@($items)) }
                        else
                            { $result[$last_key] += $items }
                        if ($last_key -ne $key) 
                            { $items = @{} }                    
                    }
                    $last_key = $key
                }
                default {
                    $item , $data = $(
                        $sep = $line.indexOf('=')
                        $line.substring(0,$sep) , $line.substring($sep+1)
                    )
                    if (!$items.ContainsKey($item))
                        { $items.Add($item,@($data))    }
                    else 
                        { $items[$item] += $data }
                }
            }
        }
        $result
    }
}
4

2 回答 2

4

变量 like$items指的是在这种情况下包含哈希表的存储位置。当您为变量分配值时,@{}您正在为变量分配对新的空哈希表的引用。如果没有其他内容引用原始哈希表,垃圾收集器将回收其内存。在哈希表上执行该Clear()方法会导致它重置为空状态。

于 2013-08-06T19:57:52.150 回答
0

首先,我认为您的意思是: $items.Clear() 而不是 $items = $items.Clear()

我得仔细看看,因为我还没有看到任何可疑的东西,但我只是想让你知道,为了回答一个更基本的问题,上面的所有代码几乎都是在做你能得到的将 ConvertTo-Json 和 ConvertFrom-Json cmdlet 应用于内存中的哈希表和正在存储的文件时,Powershell 中的几行代码。试一试,你就会明白我的意思。

于 2013-08-06T20:38:43.047 回答