【问题标题】:Powershell: replacing in strings using a hashtablePowershell:使用哈希表替换字符串
【发布时间】:2011-11-19 16:31:21
【问题描述】:

好的,所以我已经建立了一个哈希表,其中名称是要替换的内容,键是要替换的内容,如下所示:

$r = @{
    "dog" = "canine";
    "cat" = "feline";
    "eric" = "eric cartman"
}

接下来我该怎么做?我试过这个:

(Get-Content C:\scripts\test.txt) | Foreach-Object {
    foreach ( $e in $r.GetEnumerator() ) {
        $_ -replace $e.Name, $e.Value
    }
} | Set-Content C:\scripts\test.txt.out

但它根本不起作用,它只是每行写三遍,没有替换任何东西。

编辑:包含 test.txt:

dog
cat
eric

test.txt.out:

dog
dog
dog
cat
cat
cat
eric
eric
eric

【问题讨论】:

  • C:\scripts\test.txt 的内容是什么??

标签: powershell replace hashtable


【解决方案1】:

根据您的文件和哈希表,您可以考虑各种优化:

  1. 您可以像这样从散列表键集合构建正则表达式:

    $regexes = $r.keys | foreach {[System.Text.RegularExpressions.Regex]::Escape($_)}
    $regex = [regex]($r.Keys -join '|')    
    

    在这样做时,您不会迭代每个键,但现在您需要知道匹配哪个键才能获得替换。另一方面,进行字符串替换而不是正则表达式替换(或更复杂的东西,如字符串拆分和连接过程)可能更快。

  2. 在 Powershell 中,您可以调用 .NET Regex::Replace 函数:

    字符串替换(字符串输入,System.Text.RegularExpressions.MatchEvaluator 求值器)

    调用这个方法你可以定义一个MatchEvaluator 像这样的脚本块:

    $callback = { $r[$args[0].Value] }
    

    在脚本块中,$args[0] 是一个System.Text.RegularExpressions.Match,因此您可以使用它的Value 属性来索引$r 哈希表。

  3. Get-Content 返回一个字符串数组,这对于-replace 运算符来说很好,但也意味着运行了一个额外的循环。 [System.IO.File]::ReadAllText 将改为返回单个字符串,因此正则表达式只需要解析一次。

    $file = [System.IO.File]::ReadAllText("C:\scripts\test.txt")
    
  4. 如果您使用Get-Content,要使用$regex.Replace(而不是-replace),您需要一个循环:

    $file = $file | % { $regex.Replace($_, $callback) }
    

    因为我不是,所以我可以使用单个替换调用:

    $file = $regex.Replace($file, $callback)
    

因此完整的脚本:

$r = @{
    "dog" = "canine";
    "cat" = "feline";
    "eric" = "eric cartman"
}


$regexes = $r.keys | foreach {[System.Text.RegularExpressions.Regex]::Escape($_)}
$regex = [regex]($regexes -join '|')

$callback = { $r[$args[0].Value] }

$file = [System.IO.File]::ReadAllText("C:\scripts\test.txt")
$file = $regex.Replace($file, $callback)
Set-Content -Path C:\scripts\test.txt.out -Value $file

【讨论】:

  • 要使其不区分大小写,请使用$regex = [regex]("(?i)" + ($regexes -join '|'))
【解决方案2】:

我是这样弄的

foreach ($i in $HashTable.Keys) {
  $myString = $myString -replace $i, $HashTable[$i]
}

【讨论】:

    【解决方案3】:

    这是一种方法:

    $file = Get-Content C:\scripts\test.txt
    foreach ($e in $r) {
      $file = $file -replace $e.Name, $e.Value
    }
    Set-Content -Path C:\scripts\test.txt.out -Value $file
    

    您看到每行 3 次的原因是嵌套的 foreach 循环。对于文件中的每一行,每个哈希表条目都运行一次替换操作。这不会更改源文件,但默认情况下它会输出替换的结果(即使没有任何更改)。

    您可以通过首先将文件读入一个变量来获得所需的功能,然后使用循环替换来更新该变量。对于文件内容,您也不需要单独的 foreach 循环;替换可以在每个哈希表条目中一次性针对全文运行。

    【讨论】:

    • 谢谢!像魅力一样工作。
    • 好点@Christian,GetEnumerator() 调用并没有真正完成任何事情。已删除。
    猜你喜欢
    • 2020-04-10
    • 2021-12-30
    • 2017-01-16
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    相关资源
    最近更新 更多