【问题标题】:How to split a string containing newlines如何拆分包含换行符的字符串
【发布时间】:2020-07-11 16:37:09
【问题描述】:

一个字符串(从 Outlook 电子邮件 body.innerText 中提取)包含嵌入的换行符。如何将其拆分为字符串数组?

我希望这个示例字符串被拆分成一个包含两 (2) 个项目的数组。相反,它变成了一个由三 (3) 个项目组成的数组,中间有一个空行。

PS C:\src\t> ("This is`r`na string.".Split([Environment]::NewLine)) | % { $_ }
This is

a string.
PS C:\src\t> "This is `r`na string.".Split([Environment]::NewLine) | Out-String | Format-Hex

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   54 68 69 73 20 69 73 20 0D 0A 0D 0A 61 20 73 74  This is ....a st
00000010   72 69 6E 67 2E 0D 0A                             ring...

【问题讨论】:

  • 按原样使用您的代码,我得到一个包含两个项目的数组。实际电子邮件内容中是否有多个连续的换行符?
  • Out-String cmdlet 将“stuff”添加到输出中。通常在每行的末尾有cr/lf 之类的东西。当您想查看某些东西的真正输出时,请勿使用 cmdlet。 [咧嘴]
  • .Split() 方法在 split-on-this 字符串中的每个 CHAR 上拆分,而不是在整个字符串上拆分。所以你在lfcr 上有一个分裂。这就是你的额外线路的来源。 [grin] mklement0 的回答是避免该故障的一种方法。
  • @Lee_Dailey 请注意,这在 PowerShell v6+ 中不再适用(现在优先使用 [string] 分隔符的新 .NET Core 方法重载) - 这是始终更喜欢 -split 的一个很好的理由.Split().
  • @mklement0 - 谢谢你的提醒 [grin] ...我已经看到并忘记了。 [脸红]

标签: powershell newline line-breaks


【解决方案1】:

要将CRLF序列作为一个整体作为分隔符,使用-split 运算符更简单,即regex-基于:

PS> "This is `r`n`r`n a string." -split '\r?\n'
This is 
 a string.

注意:

  • \r?\n 匹配 CRLF(Windows 风格)和 LF-only(Unix 风格)换行符;如果您真的只想匹配 CRLF 序列,请使用 \r\n

    • 注意使用单引号字符串('...'),以便将包含正则表达式的字符串按原样传递给.NET正则表达式引擎;正则表达式引擎使用\ 作为转义字符;因此使用\r\n
  • PowerShell 的 -split operator[string] .NET 类型的 .Split() method 的一般优越替代品 - 请参阅 this answer


至于你尝试了什么

Windows 上的分隔符参数[Environment]::NewLine 是字符串"`r`n",即一个CRLF 序列。

  • PowerShell [Core] v6+ 中,您的命令确实 工作,因为这个字符串作为一个整体 被视为分隔符。

  • Windows PowerShell 中,正如 Steven 在 his helpful answer 中指出的那样,单个字符 - CR 和 LF 分别 被视为分隔符,从而导致在结果数组中的一个额外的空元素(CR 和 LF 之间的空字符串)中。

这种行为变化发生在 PowerShell 控制之外:.NET Core 引入了带有 [string] 类型分隔符参数的新 .Split() 方法重载,PowerShell 的重载解决算法现在使用 @987654339 选择旧重载@-typed 参数。
避免这种不可避免(尽管很少见)的无意行为变化是另一个选择 PowerShell 原生 -split operator 而不是 .NET [string] 类型的 .Split() 方法 的好理由.

【讨论】:

    【解决方案2】:

    这是因为.Split() 方法会根据它找到的任何字符进行拆分,例如:

    "first part of a string-*second part of a string".Split("-*")
    

    输出:

    first part of a string
    
    second part of a string
    

    额外元素是插入在两个拆分字符之间的空字符串。

    (感谢@mklement0,用于纠正)

    所以我只能假设这是几个因素的结果。首先[Environment]::NewLine 是两个字符 CarrigeReturn 和 LineFeed 并且来自 Outlook 的行确实使用了该行结束序列。一切都在 Windows 中。

    我能想到的解决方案有两种:

    选项 1:

    .Split([Environment]::NewLine), [Stringsplitoptions]::RemoveEmptyEntries)
    

    这显然坚持使用相同的.Split() 方法,但是添加的参数会杀死额外的元素。

    选项 2:

    使用 PowerShell -split 运算符,该运算符使用 RegEx 匹配拆分分隔符:

    "This is`r`na string." -split "`r`n"
    

    【讨论】:

    • 至于.Split() 拆分任何字符:请注意,这在 PowerShell v6+ 中不再适用(现在优先采用 [string] 分隔符的新 .NET Core 方法重载) - 这是一个很好的选择总是更喜欢 -split 而不是 .Split() 的原因。
    【解决方案3】:

    你好,

    我是 PowerShell 中的大菜鸟,但是 ...
    我写了这个

    $str_1 ="This is
    
    a string."
    $splt_1=$str_1.Split()
    $cnt_1=1
    foreach ($item in $splt_1) {
         $regEx="[a-zA-Z]"
         if ($item -cmatch $regEx){
              $Result_1=$Result_1+"$item "
         } elseif ($cnt_1 -eq 1) {
              $Result_1=$Result_1+"| "
              $cnt_1=$cnt_1+1
         }
    }
    Write-Host $Result_1
    ## OUTPUT ##
    # This is | a string.
    
    $str_2="
    This is
    
    ....a st
    
    ring...
    "
    $splt_2=$str_2.Split()
    $cnt_2=1
    foreach ($item in $splt_2) {
         $regEx="[a-zA-Z]"
         if ($item -cmatch $regEx){
              $cnt_2=1
              $Result_2=$Result_2+"$item "
         } elseif ($cnt_2 -eq 1) {
              $Result_2=$Result_2+"| "
              $cnt_2=$cnt_2+1
         }
    }
    Write-Host $Result_2
    ## OUTPUT ##
    # | This is | ....a st | ring... |
    
    

    希望对你有帮助...

    PS:

    我才意识到我忘记了结果.....

    
    $Result_1.Split("|")
    ## OUTPUT ##
    This is
     a string.
    
     $Result_2.Split("|")
     ## OUTPUT ##
     This is
     ....a st
     ring...
    
    

    EOF

    阿克塞尔埃里克。

    【讨论】:

    • 在您看到其他 2 个通过单行和一些解释解决问题的答案之后,是什么让您认为您必须发布此答案?您能否就如何解决问题以及为什么需要这么多行代码来解决这个简单的任务添加一些解释?您的解决方案有哪些优势?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-25
    • 2019-06-03
    相关资源
    最近更新 更多