【问题标题】:Split a string with spaces on a new line in PowerShell在 PowerShell 中的新行上拆分带有空格的字符串
【发布时间】:2017-06-09 17:51:30
【问题描述】:

我正在编写一个 PowerShell 脚本,在该脚本中我输入一个长字符串(来自 CSV 文件),格式为:

第一组名称
第二组名称
第三组名称
...

我正在尝试解析它

($entry.'Group Name').split("`n ") | %{
    if ($_) {
        # Do something with the group name
        $_
    }
}

我想得到如下输出:

第一组名称
第二组名称
第三组名称
...

但结果是:

集团
一个
名称
集团
两个
...

【问题讨论】:

  • 另外,我不太清楚如何格式化html中的代码,所以$应该是$_
  • 这个写的不清楚。请显示 $entry 是如何填充的,显示原始 CSV 格式,并创建一个 minimal reproducible example

标签: powershell


【解决方案1】:

如果我没看错,您对.Split 的调用会同时传入`n 和空格字符。因此,您实际上是在要求 PowerShell 将"Group One Name" 之类的字符串转换为@("Group", "One", "Name") 之类的列表。

如果$entry 是一条记录,并且您为“第一组名称”、“第二组名称”和“第三组名称”中的每一个运行此行一次,那么您可能不需要调用.Split —— 直接使用 $entry.'Group Name'

【讨论】:

    【解决方案2】:

    考虑使用 switch 语句。就个人而言,我认为使用一个会使您的代码更具可读性/可维护性:

    [System.Array] $arrCSVData = @();
    
    $arrCSVData = Import-CSV -LiteralPath '---your .csv path ---';
    
    switch ( $arrCSVData ) {
    
        { $_.'Group Name' -eq 'Group One Name' } {
            # Do something with group #1.
            break;
            }
    
        { $_.'Group Name' -eq 'Group Two Name' } {
            # Do something with group #2.
            break;
            }
    
        } #switch
    

    这显然缺乏对 CSV 导入的错误处理...

    【讨论】:

      【解决方案3】:

      如果我理解正确,您只需要从现有代码中删除空格即可。

      .split("`n ")
      

      应该是:

      .split("`n")
      

      现有代码同时使用 new linespace 作为分隔符来分割字符串。

      【讨论】:

        【解决方案4】:

        String.Split() 中的字符串参数是要拆分的字符列表,而不是要匹配然后拆分的字符序列。您现有的代码将在换行符处拆分,并将在空格处拆分。

        如果您只想在换行符处拆分,请使用:

        .split("`n")
        

        如果你想在换行符后面紧跟一个空格的字符序列上进行拆分,你可以使用Regex.Split():

        [Regex]::Split($entry.'Group Name',"`n ") | ...
        

        或者,您可以使用-split 运算符,它也按字符串而不是字符列表进行分割:

        $entry.'Group Name' -split "`n "
        

        【讨论】:

          【解决方案5】:

          我认为您需要 `r Windows 转义字符来换行。

          【讨论】:

            【解决方案6】:

            通过接受Bacon Bits' helpful answer,您已经表明它解决了您的问题,但是当您通过"`n " 时,您的意思仍然存在问题 - 即,一个 2 字符的 PowerShell字符串 - 到 [string] 类的 .Split() 方法。

            这个答案使得 经常 使用 PowerShell 自己的 -split operator 而不是 .Split() method,因为它:

            • 使用常规 PowerShell 运算符语法
            • 提供更多功能
            • 惊喜较少
            • 提供长期的行为稳定性

            -split.Split() 方法之间存在主要区别

            • 默认情况下,-split使用正则表达式来指定分割标准;使用 'SimpleMatch' 选项作为第三个 RHS 参数来使用 literal 字符串;相比之下,.Split() 方法接受文字字符串。

            • 还有一个一元形式的-split,它被任何运行的空格分割并忽略前导和尾随空格,类似于awk的默认行为;这相当于调用'...'.Split([string[]] $null, 'RemoveEmptyEntries')

            • -split 默认不区分大小写(在 PowerShell 中很常见);使用-csplit 形式进行区分大小写的匹配;相比之下,.Split()始终区分大小写

            • -split 接受 array-valued LHS,返回由拆分 LHS 的元素产生的令牌数组的串联。 p>

            • -split 隐式将 LHS 转换为字符串;相比之下,.Split() 只能在已经是 [string] 的东西上调用。

            注意:两者 -split.Split() 都允许您使用可选的第二个参数来限制返回的标记数量,它只拆分输入字符串的 部分 ,在返回数组的最后一个元素中报告输入字符串的其余部分。

            有关完整故事,请参阅Get-Help about_Split

            .Split() 方法有一个优点,但是:它比-split 运算符更快;所以,如果 .Split() 的功能在给定场景下已经足够了,你可以用它加快速度。

            示例:

            注意:在下面使用正则表达式的示例中,使用单引号字符串,LF字符表示为正则表达式转义序列 @987654353 @ 而不是 `n 转义序列 PowerShell 在任何 双引号 字符串中支持,因为最好将正则表达式指定为 单引号 字符串,以避免混淆PowerShell 预先扩展了什么,-split 最终看到了什么。

            • 字符集合中由任意分割,作为正则表达式:"`n"(LF ) 还有 " "(一个空格):

              • "one two`n three four" -split '[\n ]' 相当于
                @( 'one', 'two', '', 'three', 'four' )
            • 字符串分割,指定为正则表达式"`n ":

              • "one two`n three four" -split '\n ' 相当于
                @( 'one two', 'three four' )
            • 字符串文字分割"`n ",使用SimpleMatch 选项:

              • "one two`n three four" -split "`n ", 0, 'SimpleMatch' 产生与上述相同的结果;请注意,0 是要返回的令牌数量参数,出于语法原因必须在此处指定; 0 表示应该返回所有个令牌。
            • 在分隔符正则表达式中使用捕获组 ((...)) 以在结果数组中包含(部分)分隔符

              • 'a/b' -split '(/)' 相当于 @('a', '/', 'b')
              • 或者,使用 肯定的前瞻断言 ((?=...))使分隔符成为元素的一部分'a/b/c' -split '(?=/)' 产生相当于
                @( 'a', '/b', '/c' )
            • 限制令牌数量

              • 'one two three four' -split ' ', 3 产生等价于
                @( 'one', 'two', 'three four' ),即第三个令牌接收输入字符串的剩余部分。

              • 警告:通过分隔符正则表达式中的捕获组捕获的分隔符(部分)元素不会计入指定限制;例如,
                'a/b/c' -split '(/)', 2 产生 @( 'a', '/', 'b/c' ),即总共 3 个元素。

            • 被任意一行的空格分割(一元形式)

              • -split "`n one `n`n two `t `t three`n`n" 相当于
                @( 'one', 'two', 'three' )

            String.Split()-方法陷阱:

            访问 .NET Framework 的方法如果需要是一个很好的选择,它允许您在 PowerShell 中完成大部分已编译的 .NET 语言可以完成的工作。
            然而,PowerShell 必须在幕后做一些通常很有帮助的事情,但也可能是陷阱

            例如,'foo'.Split("`n ") 导致 PowerShell 在调用 .Split()(最接近的方法重载之间的匹配),这可能是意外的。

            您的意图可能是按 string "`n " 拆分,但调用的方法重载最终将您的字符串解释为 单个字符集其中任何一个分割输入。

            顺便说一句,跨平台的 PowerShell Core 版本有一个额外的 .Split() 重载,确实现在直接采用 [string] 参数,因此同一个调用的行为不同在那里。

            这种不受 PowerShell 控制的变化行为本身就是选择纯 PowerShell 解决方案的一个很好的理由 - 要了解为什么这些变化不受 PowerShell 控制,请参阅this GitHub issue。 p>

            可以通过显式键入来避免此类陷阱,但这既麻烦又容易忘记。
            举个例子:

            Windows PowerShell 中,如果你真的想用 string "`n " 分割,你需要这样做:

            PS> "one`n two".Split([string[]] "`n ", 'None')
            one
            two
            

            注意[string[]] 的必要强制转换 - 即使只传递 一个 字符串 - 以及选项参数 (None) 的必需使用。

            相反,如果您想在 PowerShell Core 中按 字符集 进行分割:

            PS> "one`ntwo three".Split([char[]] "`n ")
            one
            two
            three
            

            如果没有 [char[]] 演员表,"`n " 将被视为一个单个字符串以进行分割。

            【讨论】:

              猜你喜欢
              • 2017-07-15
              • 2015-11-26
              • 1970-01-01
              • 1970-01-01
              • 2016-09-04
              • 2012-09-14
              • 2014-02-15
              • 2022-01-26
              相关资源
              最近更新 更多