在PowerShell中选择一个前x个字符

时间:2018-10-27 10:31:53

标签: powershell substring

$a类似于“拐角”或“特殊拐角”,但可能只要诸如“标准窗开口多达37个”之类的东西,这意味着简单的Substring()就不会如果想在$a中查找前20个字符(这很重要),则不起作用(无论如何我都知道)。

我发现这是专为我想要的东西而设计的,但这只是给我

  

“ char [] ToCharArray(),char [] ToCharArray(int startIndex,int length)”

我不知道如何使其正常运行。

($a.ToCharArray | select -First 20) -join ""

4 个答案:

答案 0 :(得分:4)

字符串没有.ToCharArray 属性。您所使用的将为您带来该方法的重载。 [ grin ]尝试输入带引号的字符串,添加一个点,然后查看所有显示的内容。

您想要的是.ToCharAray() 方法

因此,将那些缺少的括号添加到调用中,它将起作用。 [咧嘴]

此外,在这种情况下,您确实应该使用-join字符串运算符的“最前面”版本。 “背后”版本用于添加定界符。看看差异[都给出相同的结果] ...

  • -join ('Standard Window Openings up to 37'.ToCharArray() | Select-Object -First 20)
  • ('Standard Window Openings up to 37'.ToCharArray() | Select-Object -First 20) -join ''

第一个示例更适合您的实际目标。

答案 1 :(得分:3)

Lee_Daily's helpful answer很好地解释了您的尝试所存在的问题,并提供了可行的解决方案,其中包括使用-join一元形式的解决方案。

只为将来的读者拼写 为什么仅使用.Substring()并不是实现提取-的选择至多 -N个字符。逻辑:尝试提取超出输入字符串长度的子字符串会导致 exception

PS> 'abc'.Substring(0, 2) # OK
ab

PS> 'abc'.Substring(0, 4) # !! Exception, because at most 3 chars. can be extracted
Exception [...]: Index and length must refer to a location within the string. [...]

您使用带有Select-Object管道解决问题的方法有点笨拙。

下面是使用表达式的效果更好的替代方案。


Esperento's helpful answer 提供了性能最佳的解决方案,仅使用.NET功能,尽管它有点“嘈杂”,因为它需要嵌套方法调用和一个变量(而不是文字)作为输入,因为该变量必须在嵌套方法调用中引用。
下面的方法是PowerShell惯用的。

LotPings在评论中基于以下事实提供了一种简洁的解决方案:字符串可以隐式被视为字符数组,因此 array切片可以应用;请注意,索引是基于 0

PS> -join 'abc'[0..1] 
ab

PS> -join 'abc'[0..3]  # equivalent of: 'abc'.Substring(0, 4), but by default without error
abc

范围表达式0..3的计算结果为数组0, 1, 2, 3,导致指定索引处的字符作为字符数组返回,-join然后重新组装为字符串。

默认情况下,PowerShell 忽略索引超出数组范围,但 caveat 如果Set-StrictMode -Version 3或更高版本有效,则以上内容也会导致错误


Set-StrictMode 不敏感的性能更好的替代方法是-replace运算符与正则表达式一起使用(正则表达式)。
也就是说,此解决方案是有点晦涩

PS> 'abc' -replace '(?<=.{2}).+' # equivalent of 'abc'.Substring(0, 2)
ab

PS> 'abc' -replace '(?<=.{4}).+' # always-safe equivalent of 'abc'.Substring(0, 4)
abc
  • .{4}在字符串的开头与4个字符(.)完全匹配(隐式),而不在匹配项((?<=...)中包括这些字符,后置断言); .+然后匹配所有剩余字符(一个或多个)。

  • 的净效果是,所有个字符超过4个的输入字符串都将第5个字符 中的所有替换为空字符串(由于没有替换操作数),实际上仅保留前4个字符。

  • 具有少于4个字符的输入字符串按原样传递(无需提取)。

对于 多行输入字符串,还需要做更多的工作(内联选项(?s)使.匹配换行符({{ 1}})):

`n

还考虑使用简单的帮助器功能

PS> "a`nbc" -replace '(?s)(?<=.{3}).+' # extract first 3 chars as string: "a`n"
a
b

请注意,您需要使用参数语法(类似于Shell,以空格分隔的参数)来调用它,就像在PowerShell中使用任何函数一样:

# Safe equivalent of:
#    $String.Substring($Start)
#    $String.Substring($Start, $Length)
function substr ([string] $String, [int] $Start = 0, [int] $Length = -1) {
  if ($Length -eq -1 -or $Start + $Length -ge $String.Length) {
    $String.Substring($Start)
  }
  else {
    $String.Substring($Start, $Length)
  }
}

最后,请注意,有an RFC for introducing string-manipulation cmdlets(尚未从PowerShell Core 6.2.0-preview.1开始实施),其中建议使用PS> substr 'abc' -Length 2 # same as: substr abc 0 2 / substr -String abc -Start 0 -Length 2 ab PS> substr 'abc' -Length 4 abc cmdlet来进行有效的子字符串操作在管道中

答案 2 :(得分:2)

只需这样做:

$a.Substring(0, [Math]::Min($a.Length, 20))

答案 3 :(得分:0)

旧问题,但包括我的.Net正则表达式方法,以防万一。

[Regex]::Match($a,'.{1,4}').Value