简体   繁体   English

Substring in PowerShell 截断字符串长度

[英]Substring in PowerShell to truncate string length

Is it possible in PowerShell, to truncate a string, (using SubString() ?), to a given maximum number of characters, even if the original string is already shorter ?是否有可能在 PowerShell 中将字符串截断(使用SubString() ?)到给定的最大字符数,即使原始字符串已经更短了?

For example:例如:

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

The truncation is working for hello and good morning , but I get an error for hi .截断适用于hellogood morning ,但我收到hi的错误。

I would like the following result:我想要以下结果:

hell
good
hi

You need to evaluate the current item and get the length of it.您需要评估当前项目并获得它的长度。 If the length is less than 4 then use that in the substring function.如果长度小于 4,则在 substring 函数中使用它。

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

Or you could just keep it simple, using PowerShell's alternative to a ternary operator:或者你可以保持简单,使用 PowerShell 替代三元运算符:

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

While all the other answers are "correct", their efficiencies go from sub-optimal to potentially horrendous.虽然所有其他答案都是“正确的”,但它们的效率从次优到潜在的可怕。 The following is not a critique of the other answers, but it is intended as an instructive comparison of their underlying operation.以下内容不是对其他答案的批评,而是旨在对其基本操作进行有益的比较。 After all, scripting is more about getting it running soon than getting it running fast.毕竟,脚本编写更多的是让它尽快运行而不是让它快速运行。

In order:为了:

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

    This is basically the same as my offering except that instead of just returning $str when it is too short, we call substring and tell it to return the whole string.这与我的产品基本相同,只是在 $str 太短时不只是返回,我们调用 substring 并告诉它返回整个字符串。 Hence, sub-optimal.因此,次优。 It is still doing the if..then..else but just inside Min, vis.它仍在执行 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' }

    Using regular expression matching to grab the first four characters and then replace the whole string with them means that the entire (possibly very long) string must be scanned by the matching engine of unknown complexity/efficiency.使用正则表达式匹配获取前四个字符,然后用它们替换整个字符串意味着整个(可能很长)字符串必须由未知复杂性/效率的匹配引擎扫描。

    While a person can see that the '.+' is simply to match the entire remainder of the string, the matching engine could be building up a large list of backtracking alternatives since the pattern is not anchored (no ^ at the begining).虽然人们可以看到 '.+' 只是为了匹配字符串的整个剩余部分,但匹配引擎可能会建立一个大的回溯替代列表,因为模式没有锚定(开头没有 ^)。 The (not described) clever bit here is that if the string is less than five characters (four times . followed by one or more . ) then the whole match fails and replace returns $str unaltered.此处(未描述)的巧妙之处在于,如果字符串少于五个字符(四次.后跟一个或多个. ),则整个匹配失败并替换返回 $str 不变。

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

    Deliberately throwing exceptions instead of programmatic boundary checking is an interesting solution, but who knows what is going on as the exception bubbles up from the try block to the catch.故意抛出异常而不是编程边界检查是一个有趣的解决方案,但谁知道当异常从 try 块冒泡到 catch 时发生了什么。 Probably not much in this simple case, but it would not be a recommended general practice except in situations where there are many possible sources of errors (making it cumbersome to check for all of them), but only a few responses.在这个简单的情况下可能不会太多,但它不会是推荐的一般做法,除非在有许多可能的错误来源(使得检查所有错误来源很麻烦)但只有少数响应的情况下。

Interestingly, an answer to a similar question elsewhere using -join and array slices (which don't cause errors on index out of range, just ignore the missing elements):有趣的是,使用-join和数组切片在别处回答了类似问题(不会导致索引超出范围错误,只需忽略丢失的元素):

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

(or more simply) (或更简单)

-join $str[0..3]      # Prefix

could be the most efficient (with appropriate optimisation) given the strong similarity between the storage of string and char[] .鉴于stringchar[]的存储之间的强烈相似性,可能是最有效的(经过适当的优化)。 Optimisation would be required since, by default, $str[0..3] is an object[], each element being a single char, and so bears little resemblance to a string (in memory).需要优化,因为默认情况下,$str[0..3] 是一个对象[],每个元素都是单个字符,因此与字符串(在内存中)几乎没有相似之处。 Giving PowerShell a little hint could be useful,给 PowerShell 一点提示可能很有用,

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

However, maybe just telling it what you actually want,然而,也许只是告诉它你真正想要的,

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

thereby directly invoking从而直接调用

new String(char[])

is best.是最好的。

You could trap the exception:您可以捕获异常:

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

More regex love, using lookbehind:更多正则表达式爱,使用lookbehind:

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

I'm late to the party as always!我和往常一样迟到! I have used the PadRight string function to address such an issue.我已经使用 PadRight 字符串函数来解决这样的问题。 I cannot comment on its relative efficiency compared to the other suggestions:与其他建议相比,我无法评论其相对效率:

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

You can also use -replace您也可以使用-replace

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

hell
good
hi

Old thread, but I came across the same problem and ended up with the below:-旧线程,但我遇到了同样的问题,结果如下:-

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

Replace the ✓ character with whatever rogue character you want.用你想要的任何流氓角色替换 ✓ 字符。 I used the character obtained from pressing the ALT GR and backtick key on the keyboard.我使用了通过按键盘上的 ALT GR 和反引号键获得的字符。

UGH, I feel so dirty, but here it is:呃,我觉得很脏,但它是:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM