Powershell-根据索引匹配拆分和替换
Powershell- match split and replace based on index
我有一个文件
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*LM*KY
EF*12*Code1*TX*1234*RJ
我需要在文件夹中的每个文件中单独将 CD 段中的第 5 个元素从 LM 替换为 ET。元素分隔符是*,如上述示例文件内容中所述。我是 PowerShell 的新手并尝试了如下代码,但不幸的是它没有给出预期的结果。你们中的任何人都可以提供一些帮助吗?
foreach($xfile in $inputfolder)
{
If ($_ match "^CD\*")
{
[System.IO.File]::ReadAllText($xfile).replace(($_.split("*")[5],"ET") | Set-Content $xfile
}
[System.IO.File]::WriteAllText($xfile),((Get-Content $xfile -join("~")))
}
你可以捕捉到第1组比赛前的一切,然后匹配LM。
在替换中使用ET
^(CD*(?:[^*\r\n]+\*){5})LM\b
如果您不想从字面上匹配 LM,您还可以匹配除 *
或换行符之外的任何其他字符。
^(CD*(?:[^*\r\n]+\*){5})[^*\r\n]+\b
替换示例
$allText = Get-Content -Raw file.txt
$allText -replace '(?m)^(CD*(?:[^*\r\n]+\*){5})LM\b','ET'
输出
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*ET*KY
EF*12*Code1*TX*1234*RJ
这里有一种略微不同的方式......[grin]它的作用......
- 在测试文件中伪造读数
当准备好真正做到这一点时,删除整个 #region/#endregion
块并使用 Get-Content
。
- 设置常量
- 遍历导入的文本文件行
- 检查以目标模式开头的行
- 如果找到...
== 使用 [regex]::Escape()
转义旧值以处理星号
== 用新值替换转义的旧值
== 输出该行的新版本
- 如果未找到,则按原样输出行
- 将所有行存储到
$OutStuff
var
- 在屏幕上显示
代码...
#region >>> fake reading in a plain text file
# in real life, use Get-Content
$InStuff = @'
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*LM*KY
EF*12*Code1*TX*1234*RJ
'@ -split [System.Environment]::NewLine
#endregion >>> fake reading in a plain text file
$TargetLineStart = 'CD*'
$OldValue = '*LM*'
$NewValue = '*ET*'
$OutStuff = foreach ($IS_Item in $InStuff)
{
if ($IS_Item.StartsWith($TargetLineStart))
{
$IS_Item -replace [regex]::Escape($OldValue), $NewValue
}
else
{
$IS_Item
}
}
$OutStuff
输出...
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*ET*KY
EF*12*Code1*TX*1234*RJ
我会将其保存到新文件[或覆盖旧文件]给用户。 [咧嘴一笑]
我有一个文件
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*LM*KY
EF*12*Code1*TX*1234*RJ
我需要在文件夹中的每个文件中单独将 CD 段中的第 5 个元素从 LM 替换为 ET。元素分隔符是*,如上述示例文件内容中所述。我是 PowerShell 的新手并尝试了如下代码,但不幸的是它没有给出预期的结果。你们中的任何人都可以提供一些帮助吗?
foreach($xfile in $inputfolder)
{
If ($_ match "^CD\*")
{
[System.IO.File]::ReadAllText($xfile).replace(($_.split("*")[5],"ET") | Set-Content $xfile
}
[System.IO.File]::WriteAllText($xfile),((Get-Content $xfile -join("~")))
}
你可以捕捉到第1组比赛前的一切,然后匹配LM。
在替换中使用ET
^(CD*(?:[^*\r\n]+\*){5})LM\b
如果您不想从字面上匹配 LM,您还可以匹配除 *
或换行符之外的任何其他字符。
^(CD*(?:[^*\r\n]+\*){5})[^*\r\n]+\b
替换示例
$allText = Get-Content -Raw file.txt
$allText -replace '(?m)^(CD*(?:[^*\r\n]+\*){5})LM\b','ET'
输出
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*ET*KY
EF*12*Code1*TX*1234*RJ
这里有一种略微不同的方式......[grin]它的作用......
- 在测试文件中伪造读数
当准备好真正做到这一点时,删除整个#region/#endregion
块并使用Get-Content
。 - 设置常量
- 遍历导入的文本文件行
- 检查以目标模式开头的行
- 如果找到...
== 使用[regex]::Escape()
转义旧值以处理星号
== 用新值替换转义的旧值
== 输出该行的新版本 - 如果未找到,则按原样输出行
- 将所有行存储到
$OutStuff
var - 在屏幕上显示
代码...
#region >>> fake reading in a plain text file
# in real life, use Get-Content
$InStuff = @'
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*LM*KY
EF*12*Code1*TX*1234*RJ
'@ -split [System.Environment]::NewLine
#endregion >>> fake reading in a plain text file
$TargetLineStart = 'CD*'
$OldValue = '*LM*'
$NewValue = '*ET*'
$OutStuff = foreach ($IS_Item in $InStuff)
{
if ($IS_Item.StartsWith($TargetLineStart))
{
$IS_Item -replace [regex]::Escape($OldValue), $NewValue
}
else
{
$IS_Item
}
}
$OutStuff
输出...
AB*00*Name1First*Name1Last*test
BC*JCB*P1*Church St*Texas
CD*02*83*XY*Fax*ET*KY
EF*12*Code1*TX*1234*RJ
我会将其保存到新文件[或覆盖旧文件]给用户。 [咧嘴一笑]