Powershell:使用哈希表替换字符串中的

Powershell:使用哈希表替换字符串中的,powershell,replace,hashtable,Powershell,Replace,Hashtable,好的,我建立了一个哈希表,其中名称是要替换的内容,键是要替换的内容,如下所示: $r = @{ "dog" = "canine"; "cat" = "feline"; "eric" = "eric cartman" } 接下来我该怎么办?我试过这个: (Get-Content C:\scripts\test.txt) | Foreach-Object { foreach ( $e in $r.GetEnumerator() ) { $_ -rep

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

$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

这里有一种方法:

$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
之所以每行都要看三次,是因为嵌套的foreach循环。对于文件中的每一行,每个哈希表条目运行一次替换操作。这不会更改源文件,但默认情况下它会输出替换的结果(即使没有更改)

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

我是这样做的

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

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

  • 您可以从哈希表键集合构建正则表达式,如下所示:

    $regexes = $r.keys | foreach {[System.Text.RegularExpressions.Regex]::Escape($_)}
    $regex = [regex]($r.Keys -join '|')    
    
    这样做不需要迭代每个键,但现在需要知道匹配了哪个键才能获得替换。另一方面,用字符串替换代替正则表达式替换(或更复杂的字符串拆分和连接过程)可能会更快

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

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

    调用此方法,您可以使用脚本块定义一个
    MatchEvaluator
    ,如下所示:

    $callback = { $r[$args[0].Value] }
    
    在scriptblock中,
    $args[0]
    是一个
    系统.Text.RegularExpressions.Match
    ,因此您可以使用其
    属性索引到
    $r
    哈希表中

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

    $file = [System.IO.File]::ReadAllText("C:\scripts\test.txt")
    
  • 如果使用了
    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
    

    C:\scripts\test.txt的内容是什么?谢谢!工作起来很有魅力。很好@Christian,GetEnumerator()调用并没有真正完成任何事情。已删除。要使其不区分大小写,请使用
    $regex=[regex](“(?i)”+($regexes-join'|')