string PowerShell中的子字符串截断字符串长度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27944302/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Substring in PowerShell to truncate string length
提问by Jér?me
Is it possible in PowerShell, to truncate a string, (using SubString()
?), to a given maximum number of characters, evenif 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
.
截断适用于hello
和good morning
,但我收到hi
.
I would like the following result:
我想要以下结果:
hell
good
hi
回答by Eduard Uta
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))
}
回答by uberkluger
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:
为了:
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. Hence, sub-optimal. It is still doing the if..then..else but just inside Min, vis.
if (4 -lt $str.length) {4} else {$str.length}
foreach ($str in "hello", "good morning", "hi") { $str -replace '(.{4}).+','' }
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.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. 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.
foreach ($str in "hello", "good morning", "hi") { $str.subString(0, [System.Math]::Min(4, $str.Length)) }
这与我的产品基本相同,只是在 $str 太短时不只是返回,我们调用 substring 并告诉它返回整个字符串。因此,次优。它仍在执行 if..then..else 但就在 Min 内部,vis。
if (4 -lt $str.length) {4} else {$str.length}
foreach ($str in "hello", "good morning", "hi") { $str -replace '(.{4}).+','' }
使用正则表达式匹配获取前四个字符,然后用它们替换整个字符串意味着整个(可能很长)字符串必须由未知复杂性/效率的匹配引擎扫描。
虽然人们可以看到 '.+' 只是为了匹配字符串的整个剩余部分,但匹配引擎可能会建立一个大的回溯替代列表,因为模式没有锚定(开头没有 ^)。这里(未描述)的巧妙之处在于,如果字符串少于五个字符(四次
.
后跟一个或多个.
),则整个匹配失败并且替换返回 $str 不变。foreach ($str in "hello", "good morning", "hi") { try { $str.subString(0, 4) } catch [ArgumentOutOfRangeException] { $str } }
故意抛出异常而不是编程边界检查是一个有趣的解决方案,但谁知道当异常从 try 块冒泡到 catch 时发生了什么。在这个简单的情况下可能不会太多,但它不会是推荐的一般做法,除非在有许多可能的错误来源(使得检查所有错误来源很麻烦)但只有少数响应的情况下。
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[]
. 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). Giving PowerShell a little hint could be useful,
考虑到string
和的存储之间的强烈相似性,可能是最有效的(经过适当优化)char[]
。需要优化,因为默认情况下,$str[0..3] 是一个对象[],每个元素都是单个字符,因此与字符串(在内存中)几乎没有相似之处。给 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.
是最好的。
回答by arco444
You could trap the exception:
您可以捕获异常:
foreach ($str in "hello", "good morning", "hi") {
try {
$str.subString(0, 4)
}
catch [ArgumentOutOfRangeException] {
$str
}
}
回答by mjolinor
You can also use -replace
你也可以使用 -replace
foreach ($str in "hello", "good morning", "hi") { $str -replace '(.{4}).+','' }
hell
good
hi
回答by Nicolas Melay
More regex love, using lookbehind:
更多正则表达式爱,使用lookbehind:
PS > 'hello','good morning','hi' -replace '(?<=(.{4})).+'
hell
good
hi