我正在开发一个PowerShell脚本,我在其中输入一个长字符串(来自CSV文件),格式如下:
第一组名称
组二名
组三名
...
我正在尝试解析它
($entry.'Group Name').split("`n ") | %{ if ($_) { # Do something with the group name $_ } }
我希望获得如下输出:
第一组名称
组二名
组三名
...
但它出现了:
集团
的一个
名称
组
两个
...
通过接受培根有用的答案你已经表示,它解决您的问题,但仍然留下你的问题意味着要发生,当你通过"`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()
是总是区分大小写.
您可以使用可选的第二个参数限制返回的标记数,该参数仅拆分输入字符串的一部分,在返回数组的最后一个元素中报告输入字符串的其余部分; 相比之下,.Split()
没有这样的选择.
-split
接受一个数组值 LHS,返回由分割LHS元素产生的令牌数组的串联.
-split
隐式将LHS转换为字符串 ; 相比之下,.Split()
只能在已经存在的东西上调用[string]
.
有关完整的故事,请参阅Get-Help about_Split
.
例子:
注意:在下面使用正则表达式的示例中,使用单引号字符串,LF字符表示为正则表达式转义序列, .Split()
而不是-split
PowerShell在任何双引号字符串中支持的转义序列,因为最好指定正则表达式作为单引号字符串,以避免在PowerShell预先扩展和.Split()
最终看到的内容之间产生混淆.
通过拆分任何在集合的字符,作为正则表达式:\n
(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
或者,使用正前向断言((...)
)以使分离器的元件的部分:'a/b' -split '(/)'
产生的等效
@('a', '/', 'b')
限制令牌数量:
(?=...)
产生等价的
'a/b/c' -split '(?=/)'
,即第三个令牌接收到输入字符串的剩余部分.
警告:通过分隔符正则表达式中的捕获组捕获的(部分)分隔符的元素不计入指定的限制; 例如,
@( 'a', '/b', '/c' )
产量'one two three four' -split ' ', 3
,即总共3个元素.
按任何空格运行(一元形式)拆分:
@( 'one', 'two', 'three four' )
产生相当于
'a/b/c' -split '(/)', 2
@( 'a', '/', 'b/c' )
- 方法陷阱:如果需要,可以访问.NET Framework的方法是一个很好的选项,允许您在PowerShell中执行大多数编译的.NET语言可以执行的操作.
但是,PowerShell必须在幕后做一些通常有用的事情,但也可能是陷阱:
例如,-split "`n one `n`n two `t `t three`n`n"
使PowerShell 在调用之前隐式地将字符串 转换@( 'one', 'two', 'three' )
为字符数组String.Split()
(方法重载中最接近的匹配),这可能是意外的.
您的意图可能是按字符串 拆分'foo'.Split("`n ")
,但调用的方法重载最终会将您的字符串解释为一组单独的字符,其中任何一个字符都要将输入拆分.
顺便说一句,跨平台的PowerShell 核心版有一个额外的"`n "
重载,并直接有一个字符串参数,所以相同的呼叫行为方式有所不同-看到一个解释.
这种在PowerShell控制之外的改变行为本身就是一个很好的理由,它更喜欢仅支持PowerShell的解决方案 - 为了解释为什么这些改变超出了PowerShell的控制范围,请参阅此GitHub问题.
你可以通过明确的输入来避免这种陷阱,但这既麻烦又容易忘记.
例证:在Windows PowerShell中,如果您真的想按字符串 拆分[char[]]
,那么您需要这样做:
PS> "one`n two".Split([string[]] "`n ", 'None') one two
不完全明显.