Sulaiman
Sulaiman

Reputation: 61

Windows Powershell script to find and replace a string after a particular string

I am currently working to convert AS3 class to JavaScript using Powershell script.

Below is the sample code needs to be converted.

package somePackageName
{
     class someClassName
     {
           // other codes
     }
}

I need the entire package block to be removed and "class someClassName{" should be converted to "function someClassName(){".

The "someClassName" can be any string.

And I need the output like this.

 function someClassName()
 {

 }

This is what I tried.

 $l1 = Get-Content $dest | Where-Object {$_ -like 'class'} 
 $arr = $l1 -split ' '  
 $n1 = "function "+ $arr[1] + "() " +$arr[2] 
 (Get-Content $dest) -creplace $l1, $n1 | Set-Content $dest 

I can able to achieve what I intended if the opening brace is in same line as the package declaration line. As Powershell checks line by line, I am stuck if the opening brace present in next line.

Upvotes: 1

Views: 504

Answers (2)

Matt
Matt

Reputation: 46700

Regex based solution

Depending on your willingness to post process this or accept leading spaces you could use this regex to remove the block outside of the class and replace with a function declaration. This is messier than it needs to be but safer since we cannot guess what // other codes is. You could just match the whole class block outright but if there are other curly braces in there it would muddy the regex.

PS M:\> (Get-Content -Raw $dest) -replace "(?sm).*?class (\w+)(.*)}",'function $1()$2'
function someClassName()
     {
           // other codes
     }

See Regex101 for more detail on what the regex is doing.

Basically dump everything until the word class (first time). Then keep everything until the last closing brace

Note the leading space in the greater portion. This is honoring the existing space. To account for this we need to calculate the indentation. Simply removing all leading space would break existing indentation in the class/function.

So a solution like this might be preferred:

# Read in the file as a single string
$raw = (Get-Content -Raw $dest)

# Using the line that has the class declaration measure the number of spaces in front of it. 
[void]($raw -match "(?m)^(\s+)class")
$leadingSpacesToRemove = $Matches[1].Length

# Remove the package block. Also remove a certain amount of leading space. 
$raw -replace "(?sm).*?class (\w+)(.*)}",'function $1()$2' -replace "(?m)^\s{$leadingSpacesToRemove}"

Less regex

Seems filtering the lines with no leading spaces is an easy way to narrow down to what you want.

Get-Content $dest | Where-Object{$_.StartsWith(" ")}

From there we still need to replace the "class" and deal with the leading spaces. For those we are going to use similar solutions to what I showed above.

# Read in the file as a single string. Skipping the package wrapper since it has no leading spaces.
$classBlock = Get-Content $dest | Where-Object{$_.StartsWith(" ")} 

# Get the class name and the number of leading spaces. 
$classBlock[0] -match "^(\s+)class (\w+)" | Out-Null
$leadingSpacesToRemove = $matches[1].Length
$className = $matches[2]

# Output the new declaration and the trimmed block. 
# Using an array to start so that piping output will be in one pipe
@("function $className()") + ($classBlock | Select -Skip 1) -replace "^\s{$leadingSpacesToRemove}"

Both solutions try to account for your exact specifications and account for the presence of weird stuff inside the class block.

Upvotes: 1

Maximilian Burszley
Maximilian Burszley

Reputation: 19644

I'd suggest using regex:

                           #class myclass -> function myclass()
@(Get-Content $dest) -creplace 'class\s(.+)', 'function $1()' |
    Set-Content $dest

This will capture the class declaration and replace it with a backreference to the class name capture.

Upvotes: 0

Related Questions