powershell 替换换行符不起作用:`n

powershell replace newline not working: `n

我有一个 gpx 文件,它只是 xml,并且想要 运行 一个 powershell 脚本来删除

    <trkpt lat="-33.483478" lon="150.159805">
    <name> p2 </name>
    <time>2021-02-23T00:00:12Z</time>
    </trkpt>
    <trkpt lat="-33.483852" lon="150.158309">
    <name> p3 </name>
    <time>2021-02-23T00:00:56Z</time>
    </trkpt>
    <trkpt lat="-33.483943" lon="150.157897">
    <name> p4 </name>
    <time>2021-02-23T00:01:07Z</time>
    </trkpt>
    <trkpt lat="-33.484066" lon="150.157592">
    <name> p5 </name>
    <time>2021-02-23T00:01:17Z</time>
    </trkpt>

每行仅以 LF 或 \n 结尾。我想删除包含换行符的<时间>节点。

我知道我有正确的换行符或 EOL,因为我可以在 Notepad++ 中清楚地看到这一点,并且其中的正则表达式完美无缺<time>(.*?)</time>\n

所以我将 powershell 与此代码一起使用:

(gc test.gpx) -replace '<time>(.*?)</time>`n', '' | Out-File -encoding ASCII processed1.gpx

我的所有研究表明 powershell 的换行符是 `n(不是 \n)。我也试过 `r`n 和双引号 "`n""`r`n" 以防万一,但它不起作用。我已经搜索过类似的问题,但他们的答案似乎不适合我。

感谢帮助!!

在你的gpx文件目录下打开电源shell

使用这个正则表达式:(?<=beginningstringname)(.*\n?)(?=endstringname)

运行 这个命令

             get-content test.gpx | %{$_ -replace "(?<=<time>)(.*?)(?=<\/time>)",""} 

然后

获取内容test.gpx | %{$_ -替换“findText”,“replaceText”}

注意:为了健壮性,始终最好使用专用的 XML 解析器来操作 XML,例如 .NET [xml] (System.Xml.XmlDocument) 类型 - 见底部。

至于你试过的

  • Get-Content (gc) reads files line by line by default, and since the resulting lines have any trailing newline removed from them, the -replace,operator 根据定义找不到任何换行符 - 而且,因为字符串(行)的 array 是作为输入提供,-replace 在每一行 上运行

    • -Raw开关添加到读取整个文件完整 ,改为 单行多行字符串
  • 虽然确实需要转义序列 `n 来表示 PowerShell 中的换行 (LF) 字符,但 只适用于expandable (double-quoted) strings ("...").

    • 虽然您 可以 将正则表达式的引号更改为 "...",但更好的方法是使用 verbatim (single-quoted) string ('...') 使用regex 转义序列 \n,表示换行符(PowerShell 只是 通过 传递给 .NET作为其正则表达式功能基础的正则表达式引擎,例如 -replace 运算符)。
    • 此外,您可能需要使用 \r?\n 来处理 Windows 格式的 CRLF 和 Unix 格式的 LF-only 换行符。

因此(注意省略替换字符串等同于传递''):

(gc -Raw test.gpx) -replace '<time>(.*?)</time>\r?\n'

XML-解析解法:

# Sample input, wrapped in a <xml> element.
# To load from a file, use. Load() with a *full file path*:
#   ($xml = [xml]::new()).Load("$PWD/test.gpx")
($xml = [xml]::new()).LoadXml(@'
<xml>
  <trkpt lat="-33.483478" lon="150.159805">
    <name> p2 </name>
    <time>2021-02-23T00:00:12Z</time>
  </trkpt>
  <trkpt lat="-33.483852" lon="150.158309">
    <name> p3 </name>
    <time>2021-02-23T00:00:56Z</time>
  </trkpt>
  <trkpt lat="-33.483943" lon="150.157897">
    <name> p4 </name>
    <time>2021-02-23T00:01:07Z</time>
  </trkpt>
  <trkpt lat="-33.484066" lon="150.157592">
    <name> p5 </name>
    <time>2021-02-23T00:01:17Z</time>
  </trkpt>
</xml>
'@)

$xml.xml.ChildNodes.ForEach({ 
  $parent = $_
  $null = $parent.ChildNodes.
    Where({ $_.name -eq 'time' }).
    ForEach({ $parent.RemoveChild($_) }) 
})

# Use $xml.Save - with a full output file path - to save the modified XML:
#    $xml.Save("$PWD/processed1.gpx")

注意:以上不会创建 pretty-printed XML 输出,即任何原始漂亮打印都将丢失。 如果需要漂亮的打印,有两个选项:

  • 在调用 .Load() / .LoadXml() 之前在 [xml] 实例上将 .PreserveWhitespace 设置为 $true - 但是,这可能会留下删除每个元素的空行。

  • 保存时重新执行漂亮的打印 - 请参阅 的底部部分。