如何在 Powershell 中使用 Regex 替换定界符和换行符之间的某些字符(而不是其他字符)?
How can I replace certain characters (and not others) between delimiters and across newlines, using Regex in Powershell?
这是一个示例:
: [
{
"yearGroupId": 13,
"educationPhaseEnum": 2,
"name": "Year Group 12",
"label": "YG 12"
},
{
"yearGroupId": 14,
"educationPhaseEnum": 2,
"name": "Year Group 13",
"label": "YG 13"
}
]
我想删除换行符和所有引号。我只想在字符串“: [”和“]”之间执行此操作。所以所需的输出将如下所示:
[ { yearGroupId: 13, educationPhaseEnum: 2, name: Year Group 12, label: YG 12 }, { yearGroupId: 14, educationPhaseEnum: 2, name: Year Group 13, label: YG 13 } ]
我试过了Powershell -NoProfile "(Get-Content -Raw .\allacts.txt) -replace '(?<=\u003a\u0020\u005b).*[\n\r\u0022].*(?=\u0020\u0020\u0020\u0020\u005d)', '' | Out-File -FilePath allacts.txt -Force -Encoding ASCII"
和大约一百个其他东西...但我无法理解它是如何工作的。我需要做什么才能让 Powershell 替换这些范围内的这些字符?在文件的其他地方我需要换行符。
谢谢。
编辑:是的,这是 JSON 数据。问题是有重复的键(我无法更改)。将其转换为 CSV 会导致 Powershell 忽略重复键并选择其中一个进入输出 CSV。直接将 JSON 导入 Excel(我需要它去的地方)会导致 Excel 拒绝它,因为它无法处理重复的键。
所以,我决定将所有内容都归为一个值,然后使用 Power Query 在另一端对其进行排序(使用逗号作为分隔符)。
你的任务需要一个dynamic-replace
操作操作,其中WindowsPowerShell(powershell.exe
) - 不同于 PowerShell (Core) 7+ (pwsh
) - 无法直接提供:
您需要在输入文件中识别感兴趣的块...
...然后仅在该块上执行所需的转换。
更新:如所示,non-dynamic单-replace
操作解决方案使用look-around断言 - 正如您尝试的那样 - 是可能的 - 但它们有点 mind-bending.
更详细地讨论了动态替换,但适用于您的情况这意味着(假设您是从 PowerShell 外部调用的,例如来自 cmd.exe
/ 批处理文件) :
powershell.exe -NoProfile -c "[regex]::Replace((Get-Content -Raw .\allacts.txt), '(?s): \[.+?\r?\n \]', { param($match) $match.Value -replace '[\r\n\"]' }) | Out-File -FilePath allacts.txt -Force -Encoding ASCII"
有关作为第二个参数传递给 [regex]::Replace()
and the ability to experiment with it, see this regex101.com page 的 block-matching 正则表达式的解释。
第三个参数中使用的正则表达式,动态替换脚本块({ ... }
),是[\r\n"]
,匹配所有CR(\r
), LF (\n
) 和 "
字符,并且由于它与 -replace
一起使用而没有替换操作数,因此有效地 删除了 它们。
您可以使用两个纯字符串模式正则表达式替换中的任何一个:
(Get-Content -Raw .\allacts.txt) -replace '(?s)(?<=: \[.*?)[\r\n"](?=.*? ])' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
参见 this regex demo。 详情:
(?s)
- RegexOptions.Singleline
使 .
可以匹配任何字符,包括换行符
(?<=: \[.*?)
- 正后视匹配紧接在 : [
字符串前面的位置,然后是尽可能少的零个或多个字符
[\r\n"]
- CR、LF 或 "
字符
(?=.*? ])
- 一个积极的前瞻,确保尽可能少的零个或多个字符紧跟在当前字符右侧的 space + ]
字符位置。
或者,如果您有 : [.."...".: [ ... ]
之类的字符串,并且您只想删除最接近的 : [
和 ]
之间的字符,您将需要使用
(Get-Content -Raw .\allacts.txt) -replace '(?s)(?<=: \[(?:(?!: \[).)*?)[\r\n"](?=.*? ])' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
请参阅 this regex demo(请参阅 上下文 选项卡)。 详情:
(?s)
- RegexOptions.Singleline
使 .
可以匹配任何字符,包括换行符
(?<=: \[(?:(?!: \[).)*?)
- 与紧接在前面的位置相匹配的正后视
: \[
- : [
字符串
(?:(?!: \[).)*?
- 任何字符,零个或多个,但次数尽可能少,不启动 : [
字符序列
[\r\n"]
- CR、LF 或 "
字符
(?=.*? ])
- 一个积极的前瞻,确保尽可能少的零个或多个字符紧跟在当前字符右侧的 space + ]
字符位置。
此处删除了匹配项。
或者,
(Get-Content -Raw .\allacts.txt) -replace '(?s)(\G(?!^)|: \[)(.*?)[\r\n"](?=.*? ])', '' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
或
(Get-Content -Raw .\allacts.txt) -replace '(?s)(\G(?!^)|: \[)((?:(?!: \[).)*?)[\r\n"](?=.*? ])', '' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
请参阅 this regex demo(不要忘记单击此处的 Context 选项卡)。这里
(?s)
- .
现在匹配任何字符
(\G(?!^)|: \[)
- 第 1 组 (</code>):上一场比赛结束或 <code>: [
字符串
((?:(?!: \[).)*?)
- 第 2 组 (</code>):任何字符,零个或多个,但次数尽可能少,不启动 <code>: [
字符序列
[\r\n"]
- CR、LF 或 "
(?=.*? ])
- 检查右边某处是否有 space + ]
。
在这种情况下,匹配将替换为组 1 + 组 2 值。
用\s*
(零个或多个白色spaces)或\s+
(一个或多个白色spaces)替换文字spaces模式,如果你想匹配任何(数量)白色spaces.
这是一个示例:
: [
{
"yearGroupId": 13,
"educationPhaseEnum": 2,
"name": "Year Group 12",
"label": "YG 12"
},
{
"yearGroupId": 14,
"educationPhaseEnum": 2,
"name": "Year Group 13",
"label": "YG 13"
}
]
我想删除换行符和所有引号。我只想在字符串“: [”和“]”之间执行此操作。所以所需的输出将如下所示:
[ { yearGroupId: 13, educationPhaseEnum: 2, name: Year Group 12, label: YG 12 }, { yearGroupId: 14, educationPhaseEnum: 2, name: Year Group 13, label: YG 13 } ]
我试过了Powershell -NoProfile "(Get-Content -Raw .\allacts.txt) -replace '(?<=\u003a\u0020\u005b).*[\n\r\u0022].*(?=\u0020\u0020\u0020\u0020\u005d)', '' | Out-File -FilePath allacts.txt -Force -Encoding ASCII"
和大约一百个其他东西...但我无法理解它是如何工作的。我需要做什么才能让 Powershell 替换这些范围内的这些字符?在文件的其他地方我需要换行符。
谢谢。
编辑:是的,这是 JSON 数据。问题是有重复的键(我无法更改)。将其转换为 CSV 会导致 Powershell 忽略重复键并选择其中一个进入输出 CSV。直接将 JSON 导入 Excel(我需要它去的地方)会导致 Excel 拒绝它,因为它无法处理重复的键。
所以,我决定将所有内容都归为一个值,然后使用 Power Query 在另一端对其进行排序(使用逗号作为分隔符)。
你的任务需要一个dynamic-replace
操作操作,其中WindowsPowerShell(powershell.exe
) - 不同于 PowerShell (Core) 7+ (pwsh
) - 无法直接提供:
您需要在输入文件中识别感兴趣的块...
...然后仅在该块上执行所需的转换。
更新:如-replace
操作解决方案使用look-around断言 - 正如您尝试的那样 - 是可能的 - 但它们有点 mind-bending.
cmd.exe
/ 批处理文件) :
powershell.exe -NoProfile -c "[regex]::Replace((Get-Content -Raw .\allacts.txt), '(?s): \[.+?\r?\n \]', { param($match) $match.Value -replace '[\r\n\"]' }) | Out-File -FilePath allacts.txt -Force -Encoding ASCII"
有关作为第二个参数传递给
[regex]::Replace()
and the ability to experiment with it, see this regex101.com page 的 block-matching 正则表达式的解释。第三个参数中使用的正则表达式,动态替换脚本块(
{ ... }
),是[\r\n"]
,匹配所有CR(\r
), LF (\n
) 和"
字符,并且由于它与-replace
一起使用而没有替换操作数,因此有效地 删除了 它们。
您可以使用两个纯字符串模式正则表达式替换中的任何一个:
(Get-Content -Raw .\allacts.txt) -replace '(?s)(?<=: \[.*?)[\r\n"](?=.*? ])' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
参见 this regex demo。 详情:
(?s)
-RegexOptions.Singleline
使.
可以匹配任何字符,包括换行符(?<=: \[.*?)
- 正后视匹配紧接在: [
字符串前面的位置,然后是尽可能少的零个或多个字符[\r\n"]
- CR、LF 或"
字符(?=.*? ])
- 一个积极的前瞻,确保尽可能少的零个或多个字符紧跟在当前字符右侧的 space +]
字符位置。
或者,如果您有 : [.."...".: [ ... ]
之类的字符串,并且您只想删除最接近的 : [
和 ]
之间的字符,您将需要使用
(Get-Content -Raw .\allacts.txt) -replace '(?s)(?<=: \[(?:(?!: \[).)*?)[\r\n"](?=.*? ])' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
请参阅 this regex demo(请参阅 上下文 选项卡)。 详情:
(?s)
-RegexOptions.Singleline
使.
可以匹配任何字符,包括换行符(?<=: \[(?:(?!: \[).)*?)
- 与紧接在前面的位置相匹配的正后视: \[
-: [
字符串(?:(?!: \[).)*?
- 任何字符,零个或多个,但次数尽可能少,不启动: [
字符序列
[\r\n"]
- CR、LF 或"
字符(?=.*? ])
- 一个积极的前瞻,确保尽可能少的零个或多个字符紧跟在当前字符右侧的 space +]
字符位置。
此处删除了匹配项。
或者,
(Get-Content -Raw .\allacts.txt) -replace '(?s)(\G(?!^)|: \[)(.*?)[\r\n"](?=.*? ])', '' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
或
(Get-Content -Raw .\allacts.txt) -replace '(?s)(\G(?!^)|: \[)((?:(?!: \[).)*?)[\r\n"](?=.*? ])', '' | Out-File -FilePath allacts.txt -Force -Encoding ASCII
请参阅 this regex demo(不要忘记单击此处的 Context 选项卡)。这里
(?s)
-.
现在匹配任何字符(\G(?!^)|: \[)
- 第 1 组 (</code>):上一场比赛结束或 <code>: [
字符串((?:(?!: \[).)*?)
- 第 2 组 (</code>):任何字符,零个或多个,但次数尽可能少,不启动 <code>: [
字符序列[\r\n"]
- CR、LF 或"
(?=.*? ])
- 检查右边某处是否有 space +]
。
在这种情况下,匹配将替换为组 1 + 组 2 值。
用\s*
(零个或多个白色spaces)或\s+
(一个或多个白色spaces)替换文字spaces模式,如果你想匹配任何(数量)白色spaces.