【问题标题】:Powershell `-replace` regex does not match newlinePowershell`-replace`正则表达式与换行符不匹配
【发布时间】:2021-12-14 01:53:23
【问题描述】:

我正在尝试使用正则表达式清理一些 html 文件(是的,我见过 the post。我一般不打算解析 html)并且我想删除所有不包含标签的行。我的脚本如下:

Remove-Item $args[1]
$text = (Get-Content -Path $args[0] -Raw)
$text = $text -replace "^\s*\r?\n"
New-Item -Path $args[1] -ItemType File -Force -Value $text

还有很多其他的东西我想替换,但我主要是在尝试修复

我可以验证内部正则表达式是否有效:VSCode(使用 JS 正则表达式而不是 powershell 的 .NET 正则表达式)使用提供的正则表达式正确匹配(并替换)有问题的行。

我知道Powershell is Special,所以我将Get-Content 的输出转换为带有嵌入换行符的原始字符串。这没有帮助。

我可以通过将正则表达式文本从 "^\s*\r?\n" 更改为 "p", "abc" 并看到 p 标记来验证其他函数(即 remove-itemnew-item)工作正常,并且其他正则表达式工作正常都变成abc标签。

此外,正则表达式\s*\r?\n 有效,所以并不是正则表达式找不到换行符。

正则表达式 \A\s*\r?\n 也不起作用,这意味着它与 PowerShell 如何查找字符串的开头\结尾有关。

发生了什么事?


<p>This is some text</p>

(the next line has a bunch of spaces)
               

<p>this is some more text</p>

作为参考,当使用 VSCode 的 JS 正则表达式引擎(我相信类似于 PCRE)时,我的正则表达式应该(并且确实)匹配上述示例的第二、第四和第五行

最后,正则表达式的反编译:

^         from the start of the string
 \s*      match any number of whitespaces
    \r?   possibly followed by a carriage return
       \n then a newline

【问题讨论】:

    标签: html regex powershell


    【解决方案1】:

    当你这样做时

    $text = (Get-Content -Path $args[0] -Raw)
    

    $text 中有行尾,您的正则表达式可以匹配它们。

    ^ 锚点也可以匹配任何行的开头,但是需要使用一个特殊的标志:

    $text = $text -replace '(?m)^\s*\n'
    

    \s 模式涵盖了回车,不用担心它们并使用\r?

    解释

    --------------------------------------------------------------------------------
      (?m)                     set flags for this block (with ^ and $
                               matching start and end of line) 
    --------------------------------------------------------------------------------
      ^                        the beginning of a "line"
    --------------------------------------------------------------------------------
      \s*                      whitespace (0 or
                               more times (matching the most amount
                               possible))
    --------------------------------------------------------------------------------
      \n                       '\n' (newline)
    

    【讨论】:

      【解决方案2】:

      Ryszard Czech's helpful answer 很好地解释了您的方法存在的问题并提供了有效的解决方案。

      本质上,您希望从文件中删除 emptyblank(全空白)行

      更简单 - 尽管速度较慢 - 解决方案 是利用 Get-Content 的默认逐行流式传输,结合许多 PowerShell 操作员对 进行操作的能力输入数组,在这种情况下它们充当过滤器

      在这种情况下,您可以利用-match operator(根据需要调整-Encoding):

      @(Get-Content -Path $args[0]) -match '\S' | Set-Content -Encoding UTF8 $args[1]
      

      上面将文件$args[0] 中包含至少一个非空白字符 (\S) 的所有行传递到Set-Content,这会将过滤后的行保存到目标文件@987654331 @。

      【讨论】:

        【解决方案3】:

        诀窍是,您实际上没有超过一行可以匹配。

        当您使用-Raw 将文件转换为字符串时,您将其变成了一行。 ^ 因此只会匹配文件的开头,因为这是正则表达式引擎可以找到的唯一字符串开头的标识符。

        解决方法是匹配上一行末尾的换行符或匹配文件的开头,然后将其转移到您的替换中,如下所示:

        $text = $text -replace "(^|\n)\s*\r?\n","$1"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-06-30
          • 2013-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多