【问题标题】:Substring in PowerShell to truncate string lengthPowerShell中的子字符串截断字符串长度
【发布时间】:2015-03-12 17:12:28
【问题描述】:

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

例如:

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

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

我想要以下结果:

hell
good
hi

【问题讨论】:

  • 如你想添加较短的字符,如果较长则删除它们?
  • 如果比较短,字符串保持原样,不需要添加字符。

标签: string powershell substring


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    你可以捕获异常:

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

    【讨论】:

      【解决方案3】:

      你也可以使用-replace

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

      【讨论】:

      • 您的输出与所要求的不符。
      【解决方案4】:

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

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

      虽然所有其他答案都是“正确的”,但它们的效率从次优变为可能非常可怕。以下不是对其他答案的批评,而是旨在对它们的基本操作进行有启发性的比较。毕竟,编写脚本更多的是让它尽快运行,而不是让它快速运行。

      按顺序:

      1.  

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

        这与我提供的基本相同,只是当它太短时,我们调用 substring 并告诉它返回整个字符串,而不是只返回 $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}).+','$1' }
        

        使用正则表达式匹配来抓取前四个字符,然后用它们替换整个字符串意味着整个(可能很长)字符串必须被未知复杂性/效率的匹配引擎扫描。

        虽然人们可以看到 '.+' 只是为了匹配字符串的整个其余部分,但匹配引擎可能正在构建大量回溯替代方案,因为模式没有锚定(开头没有 ^ )。此处(未描述)的巧妙之处在于,如果字符串少于五个字符(四次 . 后跟一个或多个 .),则整个匹配失败并且替换返回 $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[])
      

      最好。

      【讨论】:

      • uberkluger,你对其他贡献的吐槽方式非常恶心。仅仅根据表现来判断是愚蠢的。尽管如此,你并没有用数字来支持你的主张,所以我为每个答案跑了(Measure-Command{1..100000 | % {<snippet>}|Out-Null}).TotalSeconds 并发现:1)你的实际上比你称为“次优”的@Eduard 慢 2)你的最后一个建议是最慢的总而言之,3)我是最快的,因为在数组上使用运算符比迭代其元素要快,而且使用 @mjolinor 的正则表达式会更快。
      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

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

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

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

          【讨论】:

            【解决方案8】:

            哎呀,我觉得很脏,但这里是:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-08-14
              • 1970-01-01
              • 1970-01-01
              • 2011-10-02
              • 1970-01-01
              • 2011-06-23
              • 2023-02-21
              相关资源
              最近更新 更多