如何在 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.