首页 > 解决方案 > 未引用的关键规则和最佳实践

问题描述

这个问题与:
涉及变量引用和子表达式的参数模式中未引用的标记:为什么它们有时会分成多个参数?.

当我的项目可能请求时,我得到了这个Remove quotes in HashTables Keys 。ConvertTo-Expression

关键是我并不完全清楚何时应该在哈希表中实际引用键。
与参数值一样,不带引号的哈希表键的使用仅限于某些字符。
不允许使用多个字符(包括空格),例如:

$Options = @{
    Margin    = 2
    Padding   = 2
    Font-Size = 24
}

会导致错误:

Line |
   4 |      Font-Size = 24
     |          ~
     | Missing '=' operator after key in hash literal.

在某些情况下,只是字符的顺序可能会导致错误甚至陷阱,例如:

$Hashtable = @{ 
    U2 = 'YouTo'
    2U = 'ToYou'
}
$Hashtable.keys
2
U2

(这是因为U2键将被解释为一种类型,[UInt32]这意味着$HashTable.2U将正确显示值 but$HashTable.2和not。)$HashTable.'2'$HashTable.'2U'

除了我正在寻找一些记录在案的最佳实践的问题之外,我想安全地测试是否需要引用字符串,例如:

IsStringConstant 'Margin'    # True
IsStringConstant 'Font-Size' # False
IsStringConstant 'U2'        # True
IsStringConstant '2U'        # False

我一直在玩AST,但这需要我先构建一个ScriptBlock,这被认为是不安全的。

有没有办法检查字符串是否需要为哈希表键引用?

标签: powershell

解决方案


我一直在玩 AST,但这需要我先构建一个ScriptBlock,这被认为是不安全的。

[scriptblock]这(幸运的是)不正确 - 您可以从源代码生成 AST,而无需通过调用编译封闭Parser.ParseInput()

$tokens = @()
$errors = @()
$AST = [System.Management.Automation.Language.Parser]::ParseInput('U2',[ref]$tokens,[ref]$null)

在这种情况下,您实际上不需要检查 AST,您可以根据解析虚拟哈希表文字产生的令牌确定哈希表成员键是否有效:

function Test-IsValidHashtableStringLiteral
{
    param([string]$Identifier)

    $dummyTable = '@{{{0}=$()}}' -f $Identifier

    $tokens = @()
    $errors = @()
    $null = [System.Management.Automation.Language.Parser]::ParseInput($dummyTable, [ref]$tokens, [ref]$errors)

    if($errors.Count){
        # Parsing our dummy table resulted in errors, no good
        # This would be the case for `Font-Size`
        return $false
    }

    # No errors, let's ensure the member name is recognized 
    # as an identifier and not a value literal (like 2u in PowerShell >6)
    $memberName = $tokens[1]

    return $memberName.Kind -eq 'Identifier'
}

请注意:结果是特定于版本的- 换句话说,如果您使用上述技术并在 PowerShell 5.1 上运行ConvertTo-Expression您的2u示例,则生成的表达式只能在 5.1 中正常工作 - 以生成您需要的 7.0 兼容表达式在 7.0 上运行它。

好消息是解析器接口自 PowerShell 3.0 以来一直保持稳定,并且语言基础结构非常向后兼容,因此这种方法适用于从 3.0 到 7.x 的所有版本


推荐阅读