0

I am replacing multiple strings in a file. The following works, but is it the best way to do it? I'm not sure if doing multiple block expressions is a good way.

(Get-Content $tmpFile1) |
ForEach-Object {$_ -replace 'replaceMe1.*', 'replacedString1'} |
             % {$_ -replace 'replaceMe2.*', 'replacedString2'} |
             % {$_ -replace 'replaceMe3.*', 'replacedString3'} |
Out-File $tmpFile2

3 Answers 3

2

You don't really need to foreach through each replace operations. Those operators can be chained in a single command:

@(Get-Content $tmpFile1) -replace 'replaceMe1.*', 'replacedString1' -replace 'replaceMe2.*', 'replacedString2' -replace 'replaceMe3.*', 'replacedString3' |
Out-File $tmpFile2
Sign up to request clarification or add additional context in comments.

Comments

1

I'm going to assume that your patterns and replacements don't really just have a digit on the end that is different, so you might want to execute different code based on which regex actually matched. If so you can consider using a single regular expression but using a function instead of a replacement string. The only catch is you have to use the regex Replace method instead of the operator.

PS C:\temp> set-content -value @"
replaceMe1 something
replaceMe2 something else
replaceMe3 and another
"@  -path t.txt

PS C:\temp> Get-Content t.txt |
ForEach-Object { ([regex]'replaceMe([1-3])(.*)').Replace($_,
   { Param($m)
     $head = switch($m.Groups[1]) { 1 {"First"}; 2 {"Second"}; 3 {"Third"} }
     $tail = $m.Groups[2]
     "Head: $head, Tail: $tail"
   })}
Head: First, Tail:  something
Head: Second, Tail:  something else
Head: Third, Tail:  and another

This may be overly complex for what you need today, but it is worth remembering you have the option to use a function.

Comments

0

The -replace operator uses regular expressions, so you can merge your three script blocks into one like this:

Get-Content $tmpFile1 `
    | ForEach-Object { $_ -replace 'replaceMe([1-3]).*', 'replacedString$1' } `
    | Out-File $tmpFile2

That will search for the literal text 'replaceMe' followed by a '1', '2', or '3' and replace it with 'replacedString' followed by whichever digit was found (the '$1').

Also, note that -replace works like -match, not -like; that is, it works with regular expressions, not wildcards. When you use 'replaceMe1.*' it doesn't mean "the text 'replaceMe1.' followed by zero or more characters" but rather "the text 'replaceMe1' followed by zero or more occurrences ('*') of any character ('.')". The following demonstrates text that will be replaced even though it wouldn't match with wildcards:

PS> 'replaceMe1_some_extra_text_with_no_period' -replace 'replaceMe1.*', 'replacedString1'
replacedString1

The wildcard pattern 'replaceMe1.*' would be written in regular expressions as 'replaceMe1\..*', which you'll see produces the expected result (no replacement performed):

PS> 'replaceMe1_some_extra_text_with_no_period' -replace 'replaceMe1\..*', 'replacedString1'
replaceMe1_some_extra_text_with_no_period

You can read more about regular expressions in the .NET Framework here.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.