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



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

$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

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

您可以就地修改哈希表$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)从现有的哈希表键创建一个数组;@(...)确保将密钥集合复制到静态数组,因为直接在修改同一哈希表的循环中使用.Keys属性会中断。

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

然后,使用所需的名称转换在其新键名下重新创建条目:

$key -creplace '(?<!^)p{Lu}匹配给定键中的每个大写字母(p{Lu}),除了字符串的开头((?<!^)),并将其替换为后跟该字母(_$&)的_;将结果转换为大写(.ToUpper())得到所需的名称。


[1]添加重命名条目之前删除旧条目可以避免单个单词名称的问题,例如Simplest,由于 PowerShell 中 hasthables 不区分大小写,其转换后的名称SIMPLEST被视为相同名称。因此,在条目Simplest仍然存在时为条目SIMPLEST赋值实际上以现有条目为目标,然后后续$test.Remove($key)将简单地删除该条目,而无需添加新条目。
向约瑟夫Z指出问题致敬。

我想知道是否可以在原始对象上就地执行此操作?

($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案例键的情况下会失败,例如对于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

这似乎有效。 不过,我最终将东西放在一个新的哈希表中。

$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

最新更新