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

Zac*_*ach 3 powershell substring

$a会是“角落”或“特殊角”之类的东西,但可能会长到“标准窗户最多可打开37个”之类的东西,这意味着Substring()如果我无法使用简单的方法(无论如何,我都知道)想要查找中的前20个字符$a(这就是问题)。

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

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

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

($a.ToCharArray | select -First 20) -join ""
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 7

Lee_Dailey 的有用答案很好地解释了您尝试的问题,并提供了一个可行的解决方案,包括使用一元形式的解决方案-join

只是为了向未来的读者阐明为什么使用 just.Substring()不是实现最多N 个字符提取选项。逻辑:尝试提取超出输入字符串长度的子字符串会导致异常

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

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

不过,您使用管道解决该问题的Select-Object方法有点粗暴

以下是使用表达式的性能更好的替代方案。


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

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

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

# -> 'abc'
# Always-safe equivalent of: 
#   'abc'.Substring(0, 4)
-join 'abc'[0..3]  
  
Run Code Online (Sandbox Code Playgroud)

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

默认情况下,PowerShell会忽略数组边界之外的索引,但 需要注意的是,如果Set-StrictMode -Version 3或更高版本有效,则上述情况也会导致错误


一个性能更好且不敏感的替代方案Set-StrictMode是将运算符与 regex (正则表达式)一起使用-replace
也就是说,这个解决方案有些晦涩难懂

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

# -> 'abc'
# Always-safe equivalent of:
#   'abc'.Substring(0, 4)
'abc' -replace '(?<=.{4}).+' 
Run Code Online (Sandbox Code Playgroud)
  • .{4}完全匹配字符串开头的4字符 ( ) (隐式),而不在匹配中包含这些字符( ,后向断言);然后匹配所有剩余的字符(一个或多个)。.(?<=...).+

  • 最终效果是,所有超过 4 个字符的输入字符串都将从第 5 个字符开始的所有内容替换为空字符串(由于缺少替换操作数),实际上只留下前 4 个字符。

  • 包含4 个或更少字符的输入字符串按原样传递(无需提取)。

对于多行输入字符串,需要做更多的工作(内联选项也(?s)可以.匹配换行符(`n)):

# Extracts the first 3 chars, the equivalent of:  "a`nb"
"a`nbc" -replace '(?s)(?<=.{3}).+' 
Run Code Online (Sandbox Code Playgroud)

还可以考虑使用一个简单的辅助函数

function substr ([string] $String, [int] $Start = 0, [int] $Length = -1) {
  if ($Length -lt -1 -or $Start -lt 0) { # Quietly output '' for invalid arguments.
    ''
  } elseif ($Length -eq -1 -or $Start + $Length -ge $String.Length) {
    $String.Substring($Start)
  } else {
    $String.Substring($Start, $Length)
  }
}
Run Code Online (Sandbox Code Playgroud)

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

# -> 'ab'
# Same as: 
#   substr abc 0 2 
#   substr -String abc -Start 0 -Length 2
substr 'abc' -Length 2

# -> 'abc'
substr 'abc' -Length 4
Run Code Online (Sandbox Code Playgroud)


Esp*_*o57 7

去做就对了:

$a.Substring(0, [Math]::Min($a.Length, 20))
Run Code Online (Sandbox Code Playgroud)


Lee*_*ley 5

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

你想要的是.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 ''

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