powershell
  • hashmap
  • hashtable
  • powershell-v2.0
  • 2015-03-13 199 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

    相關問題