【问题标题】:How to construct hash table from file using powershell?如何使用powershell从文件构造哈希表?
【发布时间】:2012-01-06 12:05:18
【问题描述】:

我有一个文件,其中组件基线和组件名称存储如下

(Mailcomp@\My_PVOB) BL_2.1.0.9.5179@\My_PVOB
(OfficeComp@\My_PVOB) BL_2.1.0.17.6972@\MY_PVOB

实际上我需要构建一个哈希表,其中可能有类似的条目

@(Key=Mailcomp,Value=BL_2.1.0.9.5179)
@(Key=OfficeComp, Value=BL_2.1.0.17.6972)

我试图像下面这样替换

(Get-Content $BaselineFile) | foreach{ $_ -replace "@\My_PVOB[?]",''} | Out-File  $BaselineFile

然后我尝试创建哈希表,但第一个命令本身失败,我不知道如何从文件条目创建哈希表。有人可以帮我吗?

【问题讨论】:

    标签: regex powershell powershell-2.0


    【解决方案1】:

    在撰写本文时,有两个答案(一个来自 Shay Levy 和一个来自 jon Z)都非常接近,但两者都不完全正确——尽管 Shay 的答案已经被接受(!)。原因如下:

    Shay 的代码问题

    Shay 的回答过于字面,基于一个不准确的要求,该要求指定创建一个“可能包含类似条目的哈希表”:

    @(Key=Mailcomp,Value=BL_2.1.0.9.5179)
    @(Key=OfficeComp, Value=BL_2.1.0.17.6972)
    

    但是,如果要使用 PowerShell 语法,则说明不正确。现实中的需求应该是这样的:

    @{Mailcomp=BL_2.1.0.9.5179}
    @{OfficeComp=BL_2.1.0.17.6972}
    

    也就是说,第一行指定了Mailcomp的哈希keyBL_2.1.0.9.5179的哈希value。这个修改版的 Shay 代码准确地提供了:

    $hash = @{}
    Get-Content $BaselineFile | 
    Foreach-Object {
        if ($_ -match '^\(([^@]+).+\)\s([^@]+)')
        {
            $hash[$matches[1]]=$matches[2]
        }
    }
    

    这是输出:

    Name       Value
    ----       -----
    Mailcomp   BL_2.1.0.9.5179
    OfficeComp BL_2.1.0.17.6972
    

    这更容易使用,因为我现在可以访问 $hash["Mailcomp"]$hash["OfficeComp"] 来检索它们各自的值。

    Shay 代码的第二个问题是哈希条目创建本身 (@{ key=$matches[1]; value=$matches[2] })。该语句为每次迭代(即输入的每一行)创建一个单独的“迷你”哈希表。由于在他的代码中合并了隐式 Write-Output,它似乎 只能产生合理的输出。为了证明这一点——并将苹果与苹果进行比较——使用我上面的代码并将条件替换为等效于 Shay 的代码:

        if ($_ -match '^\(([^@]+).+\)\s([^@]+)')
        {
            @{ $matches[1]=$matches[2] }
        }
    

    您会发现$hash["Mailcomp"] 确实没有返回预期的BL_2.1.0.9.5179

    Jon 的代码问题

    我喜欢 jon Z 的回答;我真的。真的。但它让我想起了一个伟大的老笑话assume we have a can opener... 这是一个非常好的解决方案当且仅当输入适合一个简单的分隔符。这里不是这种情况——需要一个正则表达式(或其他机制)来按摩输入。平心而论,Jon 明确指出他正在假设一些预处理。 `纳夫说。

    【讨论】:

    • 我将验证并进行必要的修改以接受最佳答案
    【解决方案2】:

    假设你的 $baselinefile 在预处理后看起来像这样:

    Mailcomp BL_2.1.0.9.5179
    OfficeComp BL_2.1.0.17.6972
    

    这应该可行:

    $hash = @{}
    Import-Csv $BaseLineFile -header "first", "second" -delimiter " " | ForEach-Object { $hash[$_.first] = $_.second}
    $hash
    

    【讨论】:

      【解决方案3】:

      试试这个:

      Get-Content $BaselineFile | Foreach-Object { 
          if($_ -match '^\(([^@]+).+\)\s([^@]+)')
          {
              @{
                  key=$matches[1]
                  value=$matches[2]   
              }
          }
      }
      
      Name    Value
      ----    -----
      value   BL_2.1.0.9.5179
      key     Mailcomp
      value   BL_2.1.0.17.6972
      key     OfficeComp
      

      或者

      Get-Content $BaselineFile | Foreach-Object { 
      
          $value = ($_ -replace '@\\My_PVOB|\(|\)').split()
      
          @{
              key=$value[0]
              value=$value[1] 
          }
      }
      

      更新:创建一个哈希表,哈希键由第一个匹配项组成,其值为第二个匹配项:

      $ht = @{}
      
      Get-Content $BaselineFile | Foreach-Object {     
      
          if($_ -match '^\(([^@]+).+\)\s([^@]+)')
          {        
                  $ht[$matches[1]] = $matches[2]     
          }    
      }
      
      $ht
      
      Name       Value           
      ----       -----           
      Mailcomp   BL_2.1.0.9.5179 
      OfficeComp BL_2.1.0.17.6972
      

      【讨论】:

      • 再次,Levy 易于理解的答案令人震撼。它的工作伙伴,也可以理解
      • 这是未命名的哈希。如何将其存储在命名哈希中?这样我就可以处理散列中的每个值并再做一次操作
      • 您可以将结果分配给一个变量并使用其集合索引处理每个变量。比如: $h = gc... 然后 $h[0].key 等
      • 好友,正如“msorens”所提到的,您的代码有问题吗?我已经使用了您的代码中的替换方法以及我在 JonZ 中使用的剩余东西,我不确定这个理论
      猜你喜欢
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 2020-07-29
      • 1970-01-01
      相关资源
      最近更新 更多