PowerShell-使用下划线将属性名称从Pascal大小写转换为大写

时间:2018-12-17 20:59:56

标签: powershell powershell-v4.0

假设我有一个这样的对象:

$test = @{
          ThisIsTheFirstColumn = "ValueInFirstColumn"; 
          ThisIsTheSecondColumn = "ValueInSecondColumn"
         }     

最后我要结束:

$test = @{
          THIS_IS_THE_FIRST_COLUMN = "ValueInFirstColumn"; 
          THIS_IS_THE_SECOND_COLUMN = "ValueInSecondColumn"
         } 

无需手动编码新的列名。

这向我显示了我想要的值:

$test.PsObject.Properties | where-object { $_.Name -eq "Keys" } | select -expand value | foreach{ ($_.substring(0,1).toupper() + $_.substring(1) -creplace '[^\p{Ll}\s]', '_$&').Trim("_").ToUpper()} | Out-Host

结果为:

THIS_IS_THE_FIRST_COLUMN
THIS_IS_THE_SECOND_COLUMN

但是现在我似乎无法弄清楚如何将这些新值分配回该对象。

3 个答案:

答案 0 :(得分:6)

您可以按如下方式修改哈希表operator=

$test

foreach($key in @($test.Keys)) { # !! @(...) is required - see below. $value = $test[$key] # save value $test.Remove($key) # remove old entry # Recreate the entry with the transformed name. $test[($key -creplace '(?<!^)\p{Lu}', '_$&').ToUpper()] = $value } 根据现有的哈希表键创建一个数组; @($test.Keys)确保将键集合复制到静态数组,因为直接在修改同一哈希表的循环中使用@(...)属性会破坏。

循环主体保存手头输入键的值,然后以旧名称删除条目。 [1]

然后使用所需的名称转换以新的键名重新创建该条目:

.Keys匹配给定键中的每个大写字母($key -creplace '(?<!^)\p{Lu}),但字符串(\p{Lu})的开头除外,并用(?<!^)替换,后跟{那封信(_);将结果转换为大写(_$&)会产生所需的名称。


[1]在添加重命名的条目之前删除 之前的旧条目可避免使用单字名称(例如.ToUpper())的问题,其转换后的名称,Simplest被认为是相同名称,因为在PowerShell中hasthables不区分大小写。因此,在条目SIMPLEST仍然存在时为条目SIMPLEST分配一个值实际上是针对 existing 条目,然后随后的Simplest会简单地删除该条目,而无需添加了一个新的。
提示JosefZ指出问题所在。

答案 1 :(得分:2)

这似乎有效。我最终还是把东西放到了新的哈希表中。

$test = @{
          ThisIsTheFirstColumn = "ValueInFirstColumn"; 
          ThisIsTheSecondColumn = "ValueInSecondColumn"
         }  
$test2=@{}
$test.PsObject.Properties | 
    where-object { $_.Name -eq "Keys" } | 
    select -expand value | foreach{ $originalPropertyName=$_
                                    $prop=($_.substring(0,1).toupper() + $_.substring(1) -creplace '[^\p{Ll}\s]', '_$&').Trim("_").ToUpper()
                                    $test2.Add($prop,$test[$originalPropertyName])
                                  } 
$test2

答案 2 :(得分:2)

I wonder if it is possible to do it in place on the original object?

($test.PsObject.Properties|Where-Object {$_.Name -eq "Keys"}).IsSettableFalse。因此,您需要按照以下两个步骤进行操作:

$test = @{
          ThisIsTheFirstColumn = "ValueInFirstColumn"; 
          ThisIsTheSecondColumn = "ValueInSecondColumn"
         }
$auxarr = $test.PsObject.Properties |
  Where-Object { $_.Name -eq "Keys" } | 
    select -ExpandProperty value 
$auxarr | ForEach-Object { 
    $aux = ($_.substring(0,1).toupper() + 
    $_.substring(1) -creplace '[^\p{Ll}\s]', '_$&').Trim("_").ToUpper()
    $test.ADD( $aux, $test.$_)
    $test.Remove( $_)
}
$test

两步方法是必要的,因为尝试在唯一的管道中执行REMOVEADD方法会导致以下错误:

select : Collection was modified; enumeration operation may not execute.

修改。不幸的是,上述解决方案在一个单词 Pascal Case 的情况下会失败,例如Simplest = "ValueInSimplest"。这是经过改进的脚本:

$test = @{
          ThisIsTheFirstColumn = "ValueInFirstColumn"; 
          ThisIsTheSecondColumn = "ValueInSecondColumn"
          Simplest = "ValueInSimplest" # the simplest (one word) PascalCase
         }
$auxarr = $test.PsObject.Properties |
  Where-Object { $_.Name -eq "Keys" } | 
    select -ExpandProperty value
$auxarr | ForEach-Object { 
    $aux = ($_.substring(0,1).toupper() + 
      $_.substring(1) -creplace '[^\p{Ll}\s]', '_$&').Trim("_").ToUpper()
    $newvalue =  $test.$_
    $test.Remove( $_)
    $test.Add( $aux, $newvalue)
}
$test