我要替换文件中的多个字符串。如果字符串是大写字母,则替换为大写字母。如果是小写字母,请用小写字母替换。
到目前为止,我的代码如下所示。它确实可以替换,但是不区分大小写。
(Get-Content $xyx -ErrorAction Stop) | Foreach-Object {
$_ -replace 'abc001', 'abc002' -replace 'cde001', 'cde002'
} | Set-Content $xyz
有时候我要替换的字符串是大写的。因此,我需要介绍一下是否将大写字母替换为大写字母,否则替换为小写字母。
如何编写此代码?
编者注:首次发布此问题时,在替换字符串中保留原始大小写时不区分大小写的匹配要求并不明显-在发布了一些答案后,标题进行了修改
答案 0 :(得分:1)
-replace
regex运算符默认情况下区分大小写。如果要更改该行为,则需要使用正则表达式修饰符(-replace '(?-i)abc001', 'abc002'
)或更简单地使用-creplace 'abc001', 'abc002'
来使操作区分大小写。
但是,由于您此处似乎未使用正则表达式,因此我建议您使用字符串运算符.Replace()
,因为默认情况下它区分大小写。
$_.Replace('abc001', 'abc002').Replace('cde001', 'cde002')
答案 1 :(得分:1)
听起来您正在寻找的是在 matching 上不区分大小写 但保留大小写 的替换操作em>上的 。
您没有指定要匹配的字符串和替换字符串之间的确切关系,而是通过示例命令进行操作:
(Get-Content $xyx -ErrorAction Stop) -replace '(abc00)1', '${1}2' -replace
'(cde00)1', '${1}2' | Set-Content $xyz
注意:通过手头的特定替换,可以将它们合并为一个操作:
... -replace '(abc00|cde00)1', '${1}2'
鉴于-regex
默认情况下不区分大小写,因此它将匹配abc
和cde
的所有大小写变体,但使用其原始捕获它们第一个(也是唯一一个)捕获组((...)
)中的em>情况,在替换操作数中可以引用为${1}
(如果没有歧义,可以简称为$1
)。
还要注意我如何省略了ForEach-Cmdlet
调用,因为您可以将-replace
直接应用于(Get-Content ...)
返回的行数组;对于已经在内存中已满的阵列,此方法不仅更短,而且明显更快。
举一个简单的例子:
PS> 'aBc001' -replace '(abc00)1', '${1}2'
aBc002 # input case was preserved
答案 2 :(得分:0)
从另一个问题here,尝试类似的事情-
$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
原始答案使用正则表达式匹配。正则表达式的解释已在原始答案中提及。我要做的就是引入对大写和小写字母的检查,并同样替换它。
就像original answer中提到的那样,诀窍是使用-cmatch
运算符。 -cmatch
始终 区分大小写。
来到正则表达式,
^
的开头的anchor [a-z]
)。同样([A-z]
用于大写)。*
)。您可以改用+
禁止使用空字符串。$
末尾的anchor。这两个锚确保正则表达式必须匹配字符串中的每个字符。如果您只使用[a-z]*
,则它将匹配其中至少包含0
小写字母 somewhere 的任何字符串。这将是每个字符串。如果您的字符串也可能包含字母以外的其他内容,并且您想确保其中的每个字母为小写字母,而不是还要求字符串仅包含字母,那么您必须反转字符类,
if ($xyz -cmatch "^[^A-Z]*$") { ... }
字符类开头的^
反转类,匹配其中包括的每个字符 。因此,仅当字符串在某处包含大写字母时,此正则表达式才会失败。仍然需要-cmatch
。