全部!
我正在编写将标准 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 清除哈希表的方式感到困惑。如果我清除$items
using $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
}
}