0

I have to replace multiple strings with the same pattern, and several strings are on the same line. The replacement value should be incremental. I need to match and replace only the pattern as in the example, not requesId, nor messageId.
Input:

<requestId>qwerty-qwer12-qwer56</requestId>Ace of Base Order: Q2we45-Uj87f6-gh65De<something else...
<requestId>zxcvbn-zxcv4d-zxcv56</requestId>
<requestId>1234qw-12qw9x-123456</requestId> Stevie Wonder <messageId>1234qw-12qw9x-123456</msg
reportId>plmkjh8765FGH4rt6As</msg:reportId> something <keyID>qwer1234asdf5678zxcv0987bnml65gh</msgdc

The desired output should be:

<requestId>Request-1</requestId>Ace of Base Order: Request-2<something else...
<requestId>Request-3</requestId>
<requestId>Request-4</requestId> Stevie Wonder <messageId>Request-4</msg
reportId>ReportId-1</msg:reportId> something <keyId>KeyId-1</msg

The regex finds all matching values but I cannot make the loop and replace these values. The code I am trying to make work is:

@'
<requestId>qwerty-qwer12-qwer56</requestId>Ace of Base Order: Q2we45-Uj87f6-gh65De<something else...
<requestId>zxcvbn-zxcv12-zxcv56</requestId>
<requestId>1234qw-12qw12-123456</requestId> Stevie Wonder <messageId>1234qw-12qw12-123456</msg
reportId>plmkjh8765FGH4rt6As</msg:reportId> something <keyID>qwer1234asdf5678zxcv0987bnml65gh</msgdc
'@ | Set-Content $log -Encoding UTF8

$requestId = @{
    Count   = 1
    Matches = @()
}

$tmp = Get-Content $log | foreach { $n = [regex]::matches((Get-Content $log),'\w{6}-\w{6}-\w{6}').value
    if ($n) 
    {
        $_ -replace "$n", "Request-$($requestId.count)"
        $requestId.count++
    } $_ }
$tmp | Set-Content $log

1 Answer 1

1

You want Regex.Replace():

$requestId = 1
$tmp = Get-Content $log |ForEach-Object {
  [regex]::Replace($_, '\w{6}-\w{6}-\w{6}', { 'Request-{0}' -f ($script:requestId++) })
} 

$tmp |Set-Content $log

The script block will run once per match to calculate the substitue value, allowing us to resolve and increment the $requestId variable, resulting in the consecutive numbering you need.

You can do this for multiple patterns in succession if necessary, although you may want to use an array or hashtable for the individual counters:

$counters = { requestId = 1; keyId = 1 }
$tmp = Get-Content $log |ForEach-Object {
  $_ = [regex]::Replace($_, '\w{6}-\w{6}-\w{6}', { 'Request-{0}' -f ($counters['requestId']++) })
  [regex]::Replace($_, '\b\w{32}\b', { 'Key-{0}' -f ($counters['keyId']++) })
} 

$tmp |Set-Content $log

If you want to capture and the mapping between the original and the new value, do that inside the substitution block:

$translations = @{}
# ...

  [regex]::Replace($_, '\w{6}-\w{6}-\w{6}', { 
    # capture value we matched
    $original = $args[0].Value
    # generate new value
    $substitute = 'Request-{0}' -f ($counters['requestId']++)
    # remember it
    $translations[$substitute] = $original

    return $substitute
  })

In PowerShell 6.1 and newer versions, you can also do this directly with the -replace operator:

$requestId = 0
$tmp = Get-Content $log |ForEach-Object {
  $_ -replace '\w{6}-\w{6}-\w{6}', { 'Request-{0}' -f ($requestId++) }
}

$tmp |Set-Content $log
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Mathias, that's great. One more step ahead - how to adapt your solution to include 2 (or more) strings to be replaced? I included 2 more reportId {\w19} and KeyId {\w32} in the example input. How can I export the couple original value <> replaced value (e.g. qwerty-qwer12-qwer56 <> ReportId-1)?
Dear Mathias, the new code gives an error: Unable to index into an object of type System.Management.Automation.ScriptBlock. At line:15 char:54 + ... \w{6}-\w{6}-\w{6}', { 'Request-{0}' -f ($counters['requestId']++) })) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I checked your reply on : stackoverflow.com/questions/31312353/…, but still I was not able to fix this index. And in "@translations", what is the syntax to include the "keyId" and etc? Many thanks for your help!

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.