在PowerShell中的新行上拆分带空格的字符串

时间:2017-01-24 18:40:22

标签: powershell

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

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

我试图用

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

我希望输出如下:

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

但它出现了:

组别 一个 姓名
集团
两个
...

6 个答案:

答案 0 :(得分:6)

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

此答案通常使用PowerShell自己的-split 运算符而不是.Split() >方法 ,因为它:

  • 使用常规PowerShell运算符语法
  • 提供更多功能
  • 意外减少

-split.Split()方法之间存在关键差异:

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

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

  • -split默认情况下 不敏感 (在PowerShell中很常见);使用-csplit表单进行区分大小写的匹配;相比之下,.Split() 总是案例 - 敏感

  • 您可以使用可选的第二个参数限制返回的令牌数,该参数仅拆分输入字符串的 part ,报告输入字符串的其余部分在返回数组的最后一个元素中;相比之下,.Split()没有这样的选择。

  • -split接受数组值 LHS ,返回因拆分而导致的令牌数组的连接 LHS的要素。

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

有关完整报道,请参阅Get-Help about_Split

.Split()方法有一个优点:它比<{1}}运算符更快;所以,如果 -split的功能在给定的场景中足够,你就可以加快速度。

<强>示例:

注意:在下面使用正则表达式的示例中,使用单引号字符串,LF字符表示为正则表达式转义序列 {{ 1}}而不是PowerShell在任何双引号字符串中支持的.Split()转义序列,因为最好将正则表达式指定为单引号字符串,避免在PowerShell预先扩展的内容与\n最终看到的内容之间产生混淆。

  • 1}}(LF)以及 `n(单个空格):

    • -split相当于
      "`n"
  • 字符串 拆分,指定为正则表达式" "

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

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

    • 0相当于0
    • 或者,使用 正向前瞻断言(...)使分隔符成为元素的一部分:{{1产生相当于
      'a/b' -split '(/)'
  • 限制令牌数量

    • @('a', '/', 'b')相当于
      (?=...),即第三个令牌收到输入字符串的剩余部分。

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

  • 按任意一行空格(一元格式)拆分

    • 'one two three four' -split ' ', 3相当于
      @( 'one', 'two', 'three four' )

'a/b/c' -split '(/)', 2 - 方法陷阱:

访问.NET Framework的方法如果需要是一个很好的选择,它允许您在PowerShell中执行大多数编译的.NET语言可以执行的操作。
但是,PowerShell必须在幕后做一些通常有用的事情,但也可能是陷阱

例如,@( 'a', '/', 'b/c' )会导致PowerShell在调用之前将字符串 -split "`n one `n`n two `t `t three`n`n"隐式转换为字符数组@( 'one', 'two', 'three' )String.Split()(方法重载中最接近的匹配),这可能是意外的。

您的意图可能是由 string 'foo'.Split("`n ")拆分,但调用的方法重载最终会将您的字符串解释为aa 个别字符集任何一个其中的分割输入。

顺便提一下,跨平台的PowerShell Core 版本有一个额外的"`n "重载, 现在直接采用[char[]]参数,所以同样的呼叫在那里表现不同。

在PowerShell控制范围之外的这种改变行为本身就是一个很好的理由,更喜欢仅使用PowerShell的解决方案 - 解释为什么这些更改不在PowerShell的控制范围内,请参阅{{ 3}}

可以通过明确的输入来避免这些陷阱,但这既麻烦又容易忘记。
一个很好的例子:

Windows PowerShell中,如果您真的想通过 string .Split()进行拆分,那么您需要这样做:

"`n "

注意必要的强制转换为.Split() - 即使只传递了一个字符串 - 并且必须使用选项参数([string])。

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

"`n "

如果没有PS> "one`n two".Split([string[]] "`n ", 'None') one two 强制转换,[string[]将被视为单个字符串以进行拆分。

答案 1 :(得分:2)

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

如果$entry是单个记录,并且您为“Group One Name”,“Group Two Name”和“Group Three Name”中的每一个运行此行一次,那么您可能不需要完全致电.Split - 只需直接使用$entry.'Group Name'

答案 2 :(得分:1)

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

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

.split("`n")

如果要分隔换行符的字符序列,后面紧跟空格,可以使用Regex.Split()

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

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

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

答案 3 :(得分:0)

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

[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导入的错误处理......

答案 4 :(得分:0)

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

.split("`n ")

应该是:

.split("`n")

现有代码使用新行空间作为分隔字符串的分隔符。

答案 5 :(得分:0)

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