powershell
  • hashmap
  • hashtable
  • powershell-v2.0
  • 2015-03-13 115 views 0 likes 
    0

    假设我有一个散列表:哈希表键语法来引用嵌入哈希表元素

    $tokens = @{ 
        Id=9999; 
        Title="Lorem ipsum dolor sit amet"; 
        [email protected]{Name="John Doe"; Email='[email protected]'}; 
        [email protected]{Name="Jane Doe"; Email='[email protected]'} 
    } 
    

    而且,我想填充的模板,与所述对应的散列表的值替换令牌(例如__Title__):

    /* 
    Author:  __Author.Name__ <__Author.Email__> 
    Analyst: __Analyst.Name__ <__Analyst.Email__> 
    Request: __Title__ [__Id__] 
    */ 
    ... 
    

    应该改为:

    /* 
    Author:  John Doe <[email protected]> 
    Analyst: Jane Doe <[email protected]> 
    Request: Lorem ipsum dolor sit amet [9999] 
    */ 
    

    有没有办法来指代ŧ o在“父”哈希表中嵌入哈希表的元素?例如,$tokens['Author.Email']不起作用。

    代码:

    ... 
    return [regex]::Replace($template, '__(?<tokenName>\w+)__', { 
        # __TOKEN__ 
        param($match) 
    
        $tokenName = $match.Groups['tokenName'].Value 
    
        if ($tokens[$tokenName]) { 
        # matching token returns value from hashtable; 
        works for simple keys `$tokens['Title']`, not complex keys `$tokens['Author.Name']` 
        return $tokens[$tokenName] 
        } 
        else { 
        # non-matching token returns token 
        return $match 
        } 
    }) 
    
    +1

    '$ tokens.author.email'是电子邮件地址。至少在PowerShell 3.0中 – Matt 2015-03-13 19:00:04

    +1

    @Matt说了什么。另外'$ tokens ['作者'] ['电子邮件']' – briantist 2015-03-13 19:03:30

    +0

    @craig你是什么意思? – Matt 2015-03-13 19:08:18

    回答

    1

    有两件事情:

    1. 你需要修复的正则表达式实际匹配的嵌套属性。现在它不需要它__(?<tokenName>[\w\.]+)__

    2. 使用Invoke-Expression来动态扩展嵌套属性。只需构建一个字符串即可表示要评估的表达式。这很好,因为它不依赖于模型对象$tokens及其属性,它们都是哈希表。它所需要的只是属性在那里的对象上解析。

    一个简短的例子如下。注意:如果模板是从一个不安全的源来,要小心这一点,净化输入第一:

    $tokens = @{ 
        Id=9999; 
        Title="Lorem ipsum dolor sit amet"; 
        [email protected]{Name="John Doe"; Email='[email protected]'}; 
        [email protected]{Name="Jane Doe"; Email='[email protected]'} 
    } 
    
    $template = @" 
    /* 
    Author:  __Author.Name__ <__Author.Email__> 
    Analyst: __Analyst.Name__ <__Analyst.Email__> 
    Request: __Title__ [__Id__] 
    */ 
    "@ 
    
    function Replace-Template { 
    
    param ([string]$template, $model) 
    
        [regex]::Replace($template, '__(?<tokenName>[\w.]+)__', { 
         # __TOKEN__ 
         param($match) 
    
         $tokenName = $match.Groups['tokenName'].Value 
         $tokenValue = Invoke-Expression "`$model.$tokenName" 
    
         if ($tokenValue) { 
         # there was a value. return it. 
         return $tokenValue 
         } 
         else { 
         # non-matching token returns token 
         return $match 
         } 
        }) 
    } 
    
    Replace-Template $template $tokens 
    

    输出:

    /*
    作者:李四<[email protected]>
    分析师:李四<[email protected]>
    请求:Lorem存有悲坐阿梅德[9999]
    */

    +0

    真的很不错的解决方案; +1。我可以看到“Invoke-Expression”可能是危险的。有关如何消毒模板的任何建议? – craig 2015-03-13 21:14:48

    +0

    @craig其实,我认为它很好,只要令牌名称被限制为A-Z,a-z,0-9,_和..我不认为有任何方法可以打破表达式上下文。我正在考虑令牌名称正则表达式有点扩展。 – 2015-03-13 21:25:08

    +0

    我将'$ tokens'作为'HashTable'参数传递,所以我将代码修改为'Invoke-Expression'\'$ tokens。$ tokenName“'。否则,它完全按照我的意愿工作。另外,'$()'是反引号字符语法糖吗? – craig 2015-03-13 21:39:05

    2

    您可以直接引用的元素用点号这样

    $tokens.author.email 
    

    那么你可以做的事情还有,如果你想检查名字空例如。 注意,有一个警告:作者应该存在按预期这正是工作)

    If(!$tokens.author.name){$tokens.author.name = "Awesome Sauce"; } 
    Write-Host ("Author Name: {0}" -f $tokens.author.name) 
    

    您还可以使用哈希表表示法briantist

    $tokens['Author']['Email'] 
    

    动态更换

    的建议。

    你使用动态这个词,但我不确定你想要多远。现在让我们假设$tokens元素全都存在,我们将用here字符串替换文本。

    $text = @" 
    /* 
    Author:  __Author.Name__ <__Author.Email__> 
    Analyst: __Analyst.Name__ <__Analyst.Email__> 
    Request: __Title__ [__Id__] 
    */ 
    "@ 
    
    $text -replace "__Author\.Name__",$tokens.Author.Name -replace "__Author\.Email__",$tokens.Author.Email ` 
         -replace "__Analyst\.Name__",$tokens.Analyst.Name -replace "__Analyst\.Email__",$tokens.Analyst.Email ` 
         -replace "__Title__",$tokens.Title -replace "__Id__",$tokens.Id 
    

    但我觉得你的意思是动态的,因为所有这一切都需要有关$Tokens和源字符串知道的信息。让我知道我们现在的立场。我们可以深入这一点。

    让我们得到怪异

    让说,你知道,哈希表$tokens和源$text有共同的价值观,但你不知道他们的名字。这将根据哈希表上的键名动态填充文本。目前这只适用于只有一个散列表深度。

    ForEach($childKey in $tokens.Keys){ 
        If($tokens[$childKey] -is [System.Collections.Hashtable]){ 
         ForEach($grandChildKey in $tokens[$childKey].Keys){ 
          Write-Host "GrandChildKey = $childKey" 
          $text = $text -replace "__$childKey\.$($grandChildKey)__", $tokens.$childKey.$grandChildKey 
         } 
        } Else { 
         $text = $text -replace "__$($childKey)__", $tokens.$childKey 
        } 
    } 
    
    $text 
    

    别的东西

    此借用mike z建议约Invoke-Expression,因为它会极大地少的猜测工作。

    $output = $text 
    $placeHolders = $text | Select-String '__([\w.]+)__' -AllMatches | ForEach-Object{$_.matches} | ForEach-Object{$_.Value} 
    $placeHolders.count 
    $placeHolders | ForEach-Object { 
        $output = $output -replace [regex]::Escape($_), (Invoke-Expression "`$tokens.$($_ -replace "_")") 
    } 
    $output 
    

    搜索$text的所有字符串像东西。对于每一场比赛,用相同的点符号替换该文本。无论从样品

    输出应该与你有应该改为:

    +0

    我将如何从模板文件中找到的值动态地构造'$ token.author.name'? – craig 2015-03-13 19:10:10

    +0

    啊,我现在明白了。你可以给我看一些文字样本以供参考吗?这并不难。样本将有助于给你上下文。 – Matt 2015-03-13 19:11:14

    +0

    该文本是在问题中,但作者:__Author.Name__ <__ Author.Email __>'应该转换为'作者:John Doe <[email protected]>' – craig 2015-03-13 19:15:44

    相关问题