PowerShell 中的子字符串截断字符串长度

Substring in PowerShell to truncate string length

在 PowerShell 中是否可以将字符串截断(使用 SubString()?),以达到给定的最大字符数,如果原始字符串是 even已经更短?

例如:

foreach ($str in "hello", "good morning", "hi") { $str.subString(0, 4) }

截断适用于 hellogood morning,但我收到 hi 的错误。

我想要以下结果:

hell
good
hi

您需要评估当前项目并获取它的长度。如果长度小于 4,则在子字符串函数中使用它。

foreach ($str in "hello", "good morning", "hi") {
    $str.subString(0, [System.Math]::Min(4, $str.Length)) 
}

您可以捕获异常:

foreach ($str in "hello", "good morning", "hi") { 
  try { 
    $str.subString(0, 4) 
  }
  catch [ArgumentOutOfRangeException] {
    $str
  }
}

您也可以使用-replace

foreach ($str in "hello", "good morning", "hi") { $str -replace '(.{4}).+','' }

hell
good
hi

或者您可以保持简单,使用 PowerShell 替代三元运算符:

foreach ($str in "hello", "good morning", "hi") {
  $(if ($str.length -gt 4) { $str.substring(0, 4) } else { $str })
}

虽然所有其他答案都是 "correct",但它们的效率从次优到可能可怕。以下不是对其他答案的批评,但旨在作为对其基础操作的有益比较。毕竟,编写脚本更重要的是尽快 运行 获取它,而不是快速 运行 获取它。

依次为:

  1. foreach ($str in "hello", "good morning", "hi") {
        $str.subString(0, [System.Math]::Min(4, $str.Length))
    }
    

    这与我提供的内容基本相同,只是当 $str 太短时我们调用 substring 并告诉它 return 整个字符串,而不是仅 returning $str。因此,次优。它仍在执行 if..then..else 但只是在 Min 内部,vis.

    if (4 -lt $str.length) {4} else {$str.length}
    
  2. foreach ($str in "hello", "good morning", "hi") { $str -replace '(.{4}).+','' }
    

    使用正则表达式匹配抓取前四个字符然后用它们替换整个字符串意味着整个(可能很长)字符串必须由未知的匹配引擎扫描complexity/efficiency.

    虽然人们可以看到“.+”只是匹配字符串的整个剩余部分,但匹配引擎可能会建立一个大的回溯备选列表,因为模式没有锚定(没有 ^开始时)。这里(未描述)的巧妙之处在于,如果字符串少于五个字符(四次 . 后跟一个或多个 .),则整个匹配失败并替换 returns $str 不变。

  3. foreach ($str in "hello", "good morning", "hi") {
      try {
        $str.subString(0, 4)
      }
      catch [ArgumentOutOfRangeException] {
        $str
      }
    }
    

    故意抛出异常而不是编程边界检查是一个有趣的解决方案,但谁知道当异常从 try 块冒泡到 catch 时发生了什么。在这种简单的情况下可能不多,但它不是推荐的一般做法,除非有许多可能的错误来源(使得检查所有错误来源很麻烦),但只有少数响应。

有趣的是,在其他地方使用 -join 和数组切片(不会导致索引超出范围的错误,只是忽略丢失的元素)对类似问题的回答:

$str[0..3] -join ""   # Infix

(或更简单)

-join $str[0..3]      # Prefix
考虑到 stringchar[] 的存储非常相似,

可能是最有效的(通过适当的优化)。需要进行优化,因为默认情况下,$str[0..3] 是一个对象[],每个元素都是一个字符,因此与字符串(在内存中)几乎没有相似之处。给 PowerShell 一点提示可能会有用,

-join [char[]]$str[0..3]

然而,也许只是告诉它你真正想要什么,

new-object string (,$str[0..3]) # Need $str[0..3] to be a member of an array of constructor arguments

从而直接调用

new String(char[])

最好。

更多正则表达式爱,使用 lookbehind:

PS > 'hello','good morning','hi' -replace '(?<=(.{4})).+'
hell
good
hi

我一如既往地迟到了!我已经使用 PadRight 字符串函数来解决这样的问题。与其他建议相比,我无法评论它的相对效率:

foreach ($str in "hello", "good morning", "hi") { $str.PadRight(4, " ").SubString(0, 4) }

旧线程,但我遇到了同样的问题,结果如下:-

$str.padright(4,"✓").substring(0,4).replace("✓","")

将 ✓ 字符替换为您想要的任何流氓字符。我使用了按键盘上的 ALT GR 和反引号键得到的字符。

呃,我觉得很脏,但在这里:

-join ("123123123".ToCharArray() | select -first 42) 输出完整字符串:123123123

-join ("123123123".ToCharArray() | select -first 3) 输出前 3 个字符:123