101

How can I extract a substring using PowerShell?

I have this string ...

"-----start-------Hello World------end-------"

I have to extract ...

Hello World

What is the best way to do that?

1
  • For the opposite, I wanted everything BUT Hello World, this worked great --> $str -replace '\w\w\w\w\w.\w\w\w\w\w' Commented Aug 27, 2020 at 5:27

10 Answers 10

82

The -match operator tests a regex, combine it with the magic variable $matches to get your result

PS C:\> $x = "----start----Hello World----end----"
PS C:\> $x -match "----start----(?<content>.*)----end----"
True
PS C:\> $matches['content']
Hello World

Whenever in doubt about regex-y things, check out this site: http://www.regular-expressions.info

Sign up to request clarification or add additional context in comments.

5 Comments

I had no clue doing regex in powershell was this straightforward! Thank you so much!!!
When i try this I dont see "true" but the full line as i am trying this on a multi line varible (out put of ping). So doing a single ping and saving the reply I then just want to search for this line "Reply from 149.155.224.1: bytes=32 time<1ms TTL=128" and extract the IP address. Do you have any ideas?
Hi DevilWAH, I'd suggest starting a new question to provide context. My guess is perhaps you are seeing something related to sending an array into the -match operator? hard to tell without context. Good luck.
What if there's multiple matches?
If performance is an issue, I wouldn't use regex's. Afaik Substring() is much faster!
69

The Substring method provides us a way to extract a particular string from the original string based on a starting position and length. If only one argument is provided, it is taken to be the starting position, and the remainder of the string is outputted.

PS > "test_string".Substring(0,4)
Test
PS > "test_string".Substring(4)
_stringPS >

But this is easier...

 $s = 'Hello World is in here Hello World!'
 $p = 'Hello World'
 $s -match $p

And finally, to recurse through a directory selecting only the .txt files and searching for occurrence of "Hello World":

dir -rec -filter *.txt | Select-String 'Hello World'

1 Comment

+1: however a regex capturing whats between the start and end tags would be better e.g. "-----start-------(.+?)------end-------" (untested regex, and I'm no regex guru)
34

Not sure if this is efficient or not, but strings in PowerShell can be referred to using array index syntax, in a similar fashion to Python.

It's not completely intuitive because of the fact the first letter is referred to by index = 0, but it does:

  • Allow a second index number that is longer than the string, without generating an error
  • Extract substrings in reverse
  • Extract substrings from the end of the string

Here are some examples:

PS > 'Hello World'[0..2]

Yields the result (index values included for clarity - not generated in output):

H [0]
e [1]
l [2]

Which can be made more useful by passing -join '':

PS > 'Hello World'[0..2] -join ''
Hel

There are some interesting effects you can obtain by using different indices:

Forwards

Use a first index value that is less than the second and the substring will be extracted in the forwards direction as you would expect. This time the second index value is far in excess of the string length but there is no error:

PS > 'Hello World'[3..300] -join ''
lo World

Unlike:

PS > 'Hello World'.Substring(3,300)
Exception calling "Substring" with "2" argument(s): "Index and length must refer to a location within
the string.

Backwards

If you supply a second index value that is lower than the first, the string is returned in reverse:

PS > 'Hello World'[4..0] -join ''
olleH

From End

If you use negative numbers you can refer to a position from the end of the string. To extract 'World', the last 5 letters, we use:

PS > 'Hello World'[-5..-1] -join ''
World

1 Comment

You can use the unary form of -join too: -join 'Hello World'[-5..-1]
14
PS> $a = "-----start-------Hello World------end-------"
PS> $a.substring(17, 11)
         or
PS> $a.Substring($a.IndexOf('H'), 11)

$a.Substring(argument1, argument2) --> Here argument1 = Starting position of the desired alphabet and argument2 = Length of the substring you want as output.

Here 17 is the index of the alphabet 'H' and since we want to Print till Hello World, we provide 11 as the second argument

Comments

8

Building on Matt's answer, here's one that searches across newlines and is easy to modify for your own use

$String="----start----`nHello World`n----end----"
$SearchStart="----start----`n" #Will not be included in results
$SearchEnd="`n----end----" #Will not be included in results
$String -match "(?s)$SearchStart(?<content>.*)$SearchEnd"
$result=$matches['content']
$result

--

NOTE: if you want to run this against a file keep in mind Get-Content returns an array not a single string. You can work around this by doing the following:

$String=[string]::join("`n", (Get-Content $Filename))

Comments

5

other solution

$template="-----start-------{Value:This is a test 123}------end-------"
$text="-----start-------Hello World------end-------"

$text | ConvertFrom-String -TemplateContent $template

1 Comment

Mind blown. PowerShell has such crazy functions
2

Since the string is not complex, no need to add RegEx strings. A simple match will do the trick

$line = "----start----Hello World----end----"
$line -match "Hello World"
$matches[0]
Hello World

$result = $matches[0]
$result
Hello World

2 Comments

Extracting a known string is pointless, since you already know the string.
It is not pointless. It is handy to use if you are going to do some processing based on whether the substring exists, since it can be boiled down to a true/false, which is what a decision structure needs to proceed.
2

Often it is easier to work with [regex] directly:

This is an alternative to -match & $matches building off of Matt's answer

PS> $x = "----start----Hello World----end----"
PS> $pattern = "^-*start-*(.*?)-*end-*$"
PS> $found = [regex]::Matches($x,$pattern)
PS> $found

Groups   : {0, 1}
Success  : True
Name     : 0
Captures : {0}
Index    : 0
Length   : 44
Value    : -----start-------Hello World------end-------

PS> $found.Groups

Groups   : {0, 1}
Success  : True
Name     : 0
Captures : {0}
Index    : 0
Length   : 44
Value    : -----start-------Hello World------end-------

Success  : True
Name     : 1
Captures : {1}
Index    : 17
Length   : 11
Value    : Hello World

PS> $found.Groups[1].Value
Hello World

This allows us to find multiple match results in a string but we don't really need that functionality that grouping provides here so look-behind & look-ahead assertions would allow us to match without capturing groups:

PS> $x = "----start----Hello World----end----"
PS> $pattern = "(?<=-*start-*)[\w\s]*?(?=-*end-*)"
PS> [regex]::Match($x,$pattern).Value
Hello World

PowerShell & .NET regex is slightly different than vanilla regex so be sure to reference the quick reference guide for additional shortcuts.

Comments

0

I needed to extract a few lines in a log file and this post was helpful in solving my issue, so i thought of adding it here. If someone needs to extract muliple lines, you can use the script to get the index of the a word matching that string (i'm searching for "Root") and extract content in all lines.

$File_content = Get-Content "Path of the text file"
$result = @()

foreach ($val in $File_content){
    $Index_No = $val.IndexOf("Root")
    $result += $val.substring($Index_No)
}

$result | Select-Object -Unique

Cheers..!

Comments

0

Try This:

$mystring="------start---Hello World--end---------"
$result=@([regex]::split($mystring,'\-+'))[2]
$result

This frees you from having to count dashes, and instead uses a group of one or more dashes as a delimiter, and extracts the third field (the first field is null). The "@(" and ")" casts the result as an array (my paranoia more than necessity).

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
Please explain what you've changed to address the issue. Code-only answers are not good answers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.