-1

I have a file prototype as follows:

// <some stuff>
#define KEYWORD release01-11
// <more stuff>

How can I delete the last two characters in the same line as KEYWORD and replace them with two different characters (12 in this case), in order to end up with:

// <some stuff>
#define KEYWORD release01-12
// <more stuff>

I'm trying to use Clear-Content and Add-Content but I cannot get it to do what I need. The rest of the file needs to remain unchanged after these symbols have been replaced. Is there a better alternative?

kiryakov
  • 145
  • 1
  • 7
  • What searches have you tried? For example I just searched this site using the terms "powershell replace" and this one was right at the top: https://stackoverflow.com/questions/17144355/how-can-i-replace-every-occurrence-of-a-string-in-a-file-with-powershell – Bill_Stewart Sep 07 '21 at 11:49
  • @Bill_Stewart I also found that one, but that one changes *every* occurrence of the string, which also messes with the rest of my file. I need to limit it to only do so after the keyword. – kiryakov Sep 07 '21 at 11:54
  • Do you always want to replace the trailing number with `12` or do you need to inspect and increment the current value every time? – Mathias R. Jessen Sep 07 '21 at 11:59
  • @MathiasR.Jessen Inspect and increment to increase the version as it develops. – kiryakov Sep 07 '21 at 12:01
  • If existing searches are lacking in some way, it is good practice to _note this in your question_ and explain _why_ the results don't get you where you need to go. It is also a good idea to give a code sample of what specifically you have tried and _how_, specifically, what you tried didn't work. – Bill_Stewart Sep 07 '21 at 16:23

1 Answers1

4

Use the -replace regex operator to identify the relevant statements and replace/remove the trailing numbers:

# read file into a variable
$code = Get-Content myfile.c

# replace the trailing -XX with 12 in all lines starting with `#define KEYWORD`, with 
$code = $code -replace '(?<=#define KEYWORD .+-)\d{2}\s*$','12'

# write the contents back to the file
$code |Set-Content myfile.c

The regex construct (?<=...) is a positive lookbehind - it ensures that the following expression will only match at a position where text right behind it is #define KEYWORD followed by some characters and a -.


If you want to always increment the current value (as opposed to just replacing it with 12), we'll need some way to inspect and evaluate the current value before doing the substitution.

The [Regex]::Replace() method allows for just that:

# read file into a variable
$code = Get-Content myfile.c

$code = $code |ForEach-Object {
  # Same as before, but now we can hook into the regex engine's substitution routine
  [regex]::Replace($_, '(?<=#define KEYWORD .+-)\d{2}\s*$',{
    param($m)

    # extract the trailing numbers, convert to a numerical type
    $value = $m.Value -as [int]
    # increment the value
    $value++
    # return the new value
    return $value
  })
}

# write the contents back to the file
$code |Set-Content myfile.c

In PowerShell 6.1 and up, the -replace operator natively supports scriptblock substitutions:

$code = $code |ForEach-Object {
  # Same as before, but now we can hook into the regex engine's substitution routine
  $_ -replace '(?<=#define KEYWORD .+-)\d{2}\s*$',{
    # extract the trailing numbers, convert to a numerical type
    $value = $_.Value -as [int]
    # increment the value
    $value++
    # return the new value
    return $value
  }
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • The problem with this is that since the "release01" is also changing, I cannot include it in the regex, so running this doesn't increment the final value. – kiryakov Sep 07 '21 at 12:09
  • 1
    @peepeepoopoo Who said anything about "release01"? :) The regex pattern describes 2 digits preceded by `#define KEYWORD -` <- doesn't matter if it says `release01` or `peepeepoopoo` or `allyourbasearebelongtous` – Mathias R. Jessen Sep 07 '21 at 12:10
  • Yep, with just a bit of a change to the regex to match my exact pattern (since I for some reason changed it for this question) I got it to work. This works perfectly. Thank you! – kiryakov Sep 07 '21 at 12:13
  • @MathiasR.Jessen As a follow up question, in your regex is the positive lookbehind an exact match? Meaning if I have both `KEYWORD` and `KEYWORD_2` will this regex recognize both, or only the first. – kiryakov Sep 07 '21 at 12:51
  • @peepeepoopoo Right now it expects a space after `KEYWORD`, but you could remove that space (between `KEYWORD` and `.+`) – Mathias R. Jessen Sep 07 '21 at 12:54
  • Could you please explain what the '$' in the end of your regex does? I can not for the life of me find a source explaining what it does. Moreso, removing it actually gives me better behavior, in some cases. For example `\d{2}\s*$` does not isolate the number in 'release01-11EXTRATEXT', but `\d{2}\s*` does. – kiryakov Sep 08 '21 at 06:44