22

substring complains when I try to limit a string to 10 characters which is not 10 or more characters in length. I know I can test the length but I would like to know if there is a single cmdlet which will do what I need.

PS C:\> "12345".substring(0,5)
12345

PS C:\> "12345".substring(0,10)
Exception calling "Substring" with "2" argument(s): "Index and length must refer to a location within the string.
Parameter name: length"
At line:1 char:18
+ "12345".substring( <<<< 0,10)
Ethan Post
  • 3,020
  • 3
  • 27
  • 27

6 Answers6

39

Do you need exactly a cmdlet? I wonder why you don't like getting length. If it's part of a script, then it looks fine.

$s = "12345"
$s.substring(0, [System.Math]::Min(10, $s.Length))
SteveC
  • 15,808
  • 23
  • 102
  • 173
Dmitry Tashkinov
  • 1,976
  • 19
  • 16
  • Thanks that will work fine. I was looking for "least" and "greatest" functions and was not aware of this method. – Ethan Post Feb 25 '10 at 18:27
  • 1
    It is from the .Net standard library. When you don't find a cmdlet that does what you want, check for a method that does this in .Net. – Dmitry Tashkinov Feb 25 '10 at 18:33
  • This is only correct for startIndex = 0. Otherwise, substract that from the second argument for Min. ie `@s.substring(3, [System.Math]::Min(10, $s.Length - 3))` – svandragt Sep 01 '15 at 13:24
33

Using the substring function has it's limitations and requires you to first capture the length of the string. Granted this does work you can do it without that limitation.

The following will return the first 5 characters of the string

"1234567890"[0..4] -join ""     # returns the string '12345'

And this will work on strings that are shorter than desired length

"1234567890"[0..1000] -join ""  # returns the string '1234567890'
Ro Yo Mi
  • 14,790
  • 5
  • 35
  • 43
  • You answer the question in first example. Simple and easy. Thanks! (+1) But, I am not sure what your second example is trying to do - the example itself shows nothing/no change to string. Either a bad example, doesn't work as intended, or not explained adequately.. – B. Shea Apr 09 '21 at 12:09
  • 4
    @B.Shea he is showing that it won't break if the string you are truncating isn't long enough to actually truncate. Basically it's safe to use on short strings and long strings. This lets you avoid doing an if statement before truncation. – Bill Rawlinson Jul 29 '21 at 11:49
  • 1
    This is a great technique, but a `$null` string variable throws an error. Fix it by wrapping the variable in a string: `$trimmed = "$($myObject.Property)"[0..9] -join ""` – McGuireV10 May 24 '23 at 12:48
3

You can load and use other libraries and use their string functions, for example the visual basic string functions work nicely for what you want to do


call once per session >[void][reflection.assembly]::LoadWithPartialName("microsoft.visualbasic")

then use various vb string functions

>[microsoft.visualbasic.strings]::left("12345",10)
12345

or

>[microsoft.visualbasic.strings]::mid("12345",1,10)
12345
G Schmitt
  • 31
  • 1
2

The previous answers didn't suit my purposes (no offence!) so I took Denomales suggestion above and rolled it into a function which I thought I'd share:

function Trim-Length {
param (
    [parameter(Mandatory=$True,ValueFromPipeline=$True)] [string] $Str
  , [parameter(Mandatory=$True,Position=1)] [int] $Length
)
    $Str[0..($Length-1)] -join ""
}

Example usages:

"1234567" | Trim-Length 4    # returns: "1234"
"1234" | Trim-Length 99      # returns: "1234"
TechnoTone
  • 181
  • 2
  • 6
0

Thanks to Dmitry for the answer, I turned it into a function and made it so it is 1 based as opposed to 0 based.

function acme-substr ([string]$str, $start, $end) {
   $str.substring($start-1, [System.Math]::Min($str.Length-1, $end))
}

> $foo="0"*20
> $foo
00000000000000000000
> acme-substr $foo 1 5
00000
Ethan Post
  • 3,020
  • 3
  • 27
  • 27
0

How about padding first.

$s = "12345"
$s.PadRight(10).Substring(0,10).TrimEnd() # returns "12345" 
C Somers
  • 1
  • 1