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 がハッシュテーブルをクリアする方法について数分間困惑しました。$itemsを使用してクリアすると$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

0

まず第一に、$items = $items.Clear() ではなく $items.Clear() を意味していると思います

まだ疑わしいものは何も見当たらないので、詳しく調べる必要がありますが、より基本的な質問に答えるために、上記のコードはすべて、 ConvertTo-Json および ConvertFrom-Json コマンドレットをメモリ内のハッシュテーブルと保存しているファイルの両方に適用することで、Powershell で数行のコードを作成できます。試してみると、私の言いたいことがわかるでしょう。

于 2013-08-06T20:38:43.047 に答える