如何使用不区分大小写的匹配替换PowerShell中的字符串,同时保留输入大小写

如何使用不区分大小写的匹配替换PowerShell中的字符串,同时保留输入大小写,powershell,replace,text-processing,Powershell,Replace,Text Processing,我想替换文件中的多个字符串。如果字符串为大写,则替换为大写字母。如果是小写,则用小写字母替换 到目前为止,我的代码如下所示。它确实可以替换,但不能按情况替换 (Get-Content $xyx -ErrorAction Stop) | Foreach-Object { $_ -replace 'abc001', 'abc002' -replace 'cde001', 'cde002' } | Set-Content $xyz 有时我要替换的字符串是大写的。所以我需要引入一个检查,如果它是

我想替换文件中的多个字符串。如果字符串为大写,则替换为大写字母。如果是小写,则用小写字母替换

到目前为止,我的代码如下所示。它确实可以替换,但不能按情况替换

(Get-Content $xyx -ErrorAction Stop) | Foreach-Object {
  $_ -replace 'abc001', 'abc002' -replace 'cde001', 'cde002' 
} | Set-Content $xyz
有时我要替换的字符串是大写的。所以我需要引入一个检查,如果它是大写替换为小写

如何编写此代码


编者按:第一次发布此问题时,在替换字符串中保留原始大小写的同时不区分大小写匹配的要求并不十分明显-在发布一些答案后,标题后来被修改。

默认情况下,
-replace
正则表达式运算符区分大小写。如果您想更改该行为,则需要使用正则表达式修饰符(
-replace'(?-i)abc001',“abc002”
)或更简单的
-creplace'abc001',“abc002”
,使操作区分大小写

但是,由于您在这里似乎没有使用regex,因此我建议您使用字符串运算符
.Replace()
,因为默认情况下它区分大小写

$_.Replace('abc001', 'abc002').Replace('cde001', 'cde002')
从另一个问题开始,试着这样做-

$i = 0
(Get-Content $xyx -ErrorAction Stop) | Foreach-Object {
    $line = $_[$i];
    if ($line -cmatch "^[^a-z]*$")
    {
        $line -replace $Matches.Value, 'YourNewValue'.ToUpper()
    }
    elseif ($line -cmatch "^[^A-Z]*$")
    {
        $line -replace $Matches.Value, 'YourNewValue'.ToLower()
    }
    $i++    
} | Set-Content $xyz
原始答案使用正则表达式匹配。原始答案中已经提到了对正则表达式的解释。我所做的就是引入一个大写和小写的检查,并同样替换它

如中所述,诀窍是使用
-cmatch
运算符<代码>-cmatch始终区分大小写

来到regex

  • 字符串的开头(
    ^
  • 小写拉丁字母(
    [A-z]
    )的缩写。同样(
    [A-z]
    用于大写)
  • A,告知至少重复字符类0次,从而根据需要匹配尽可能多的字符(
    *
    )。您可以使用
    +
    来禁止空字符串
  • 字符串结尾的字符串(
    $
    )。这两个锚点确保正则表达式必须匹配字符串中的每个字符。如果您只使用
    [a-z]*
    ,那么这将匹配任何字符串中至少包含
    0
    小写字母的字符串。这就是每根弦
如果字符串也可能由字母以外的其他内容组成,并且希望确保其中的每个字母都是小写,而不是要求字符串仅由字母组成,则必须反转字符类,排序为:

if ($xyz -cmatch "^[^A-Z]*$") { ... }

字符类开头的
^
反转类,匹配未包含的每个字符。因此,只有当字符串中包含大写字母时,此正则表达式才会失败。尽管如此,仍然需要
-cmatch

这听起来像是一种替换操作,在匹配时不区分大小写,但在替换时保留大小写。

您没有指定要匹配的字符串之间的确切关系以及替换它们的内容,而是使用示例命令:

(Get-Content $xyx -ErrorAction Stop) -replace '(abc00)1', '${1}2' -replace 
                                              '(cde00)1', '${1}2' | Set-Content $xyz
注意:有了手头的特定替换件,可以将它们组合成一个操作:
-替换“(abc00 | cde00)1',“${1}2'

  • 假定默认情况下,
    -regex
    不区分大小写,它将匹配
    abc
    cde
    的所有大小写变体,但在第一个(也是唯一一个)捕获组(
    (…)
    )中捕获它们的原始大小写,该组可以在替换操作数中引用为
    ${1}
    (或者如果没有歧义,只需
    $1

  • 还要注意我是如何省略了
    ForEach Cmdlet
    调用的,因为您可以直接将
    -replace
    应用到
    (获取内容…
    返回的行数组中;对于内存已满的数组,这种方法不仅更短,而且速度明显更快

提供一个简单的示例:

PS> 'aBc001' -replace '(abc00)1', '${1}2'
aBc002    # input case was preserved

谢谢Vivek的代码。我不知道如何检查值是大写还是小写。在上面的代码中,它将如何知道值是大写还是小写。我使用了您的代码,例如$I=0(获取内容$xyz-ErrorAction Stop)| Foreach对象{$line=$\u[$I];if($line-cmatch“^[^a-z]*$”){$line-replace$Matches.value'abc001'.ToUpper()}elseif($line-cmatch“^[^A-Z]*$”{$line-replace$Matches.value'abc001'.ToLower()}$i++}|设置内容$xyz我肯定我做错了什么,作为一个输出,我得到了所有行中的所有abc001。这是因为对于每一行输入,您总是将值替换为
'abc001
。您总是将循环替换为
'abc001
。嗨,马特,我得到语法错误获取内容$xyz ErrorAction Stop)| Foreach对象{$\.replace(abc01,'abc02')`.replace('cde01','cde02')`}|设置内容$xyz,请您帮助我了解语法。注释中的代码有空格,我的答案没有空格。还有一个没有开头的大括号。字符串上缺少引号…我建议您使用PowerShell ISE之类的编辑器。它可以帮助在测试中突出这些问题。如果我在一行中编写此代码,它可以工作,但如果我将其打断在3行中,它给了我语法错误。))@ ASHIS:您不能在任意位置中断该行;如果有疑问,请在行的末尾放置一个<代码> <代码>以强制行继续(使PuxSek考虑下一行是当前行的延续)。