Search code examples
regexpowershellreplacecurrency

How to convert a string containing 2 numbers to currency with powershell?


I have text files that contain 2 numbers separated by a '+' sign. Trying to figure out how to replace them with currency equivalent .
Example Strings:

20+2 would be converted to $0.20+$0.02 USD

1379+121 would be> $13.79+$1.21 USD

400+20 would be $4.00+$0.20 USD

and so on.

I have tried using a few angles but they do not work or provide odd results. I tried to do it here by attempting to find by all patterns I think would come up .

.\Replace-FileString.ps1 "100+10" '$1.00+$0.10' $path1\*.txt -Overwrite
.\Replace-FileString.ps1 "1000+100" '$10.00+$1.00' $path1\*.txt -Overwrite
.\Replace-FileString.ps1 "300+30" '$3.00+$0.30' $path1\*.txt -Overwrite
.\Replace-FileString.ps1 "400+20" '$4.00+$0.20' $path1\*.txt -Overwrite

or this which just doesn't work.

Select-String -Path .\*txt -Pattern '[0-9][0-9]?[0-9]?[0-9]?[0-9]?\+[0-9][0-9]?[0-9]?[0-9]?[0-9]?' | ForEach-Object  {$_ -replace ", ", $"}  {$_ -replace "+", "+$"}

Solution

  • I tried to do it here by attempting to find by all patterns I think would come up

    Don't try this - we're humans, and we won't think of all edge cases and even if we did, the amount of code we needed to write (or generate) would be ridiculous.


    We need a more general solution here, and regex might indeed be helpful with this.

    The pattern you describe could be expressed as three distinct parts:

    1. 1 or more consecutive digits
    2. 1 plus sign (+)
    3. 1 or more consecutive digits

    With this in mind, let's start to simplifying the regex pattern to use:

    \b\d+\+\d+\b
    

    or, written out with explanations:

    \b       # a word boundary
      \d+    # 1 or more digits
      \+     # 1 literal plus sign
      \d+    # 1 or more digits
    \b       # a word boundary
    

    Now, in order to transform an absolute value of cents into dollars, we'll need to capture the digits on either side of the +, so let's add capture groups:

    \b(\d+)\+(\d+)\b
    

    Now, in order to do anything interesting with the captured groups, we can utilize the Regex.Replace() method - it can take a scriptblock as its substitution argument:

    $InputString  = '1000+10'
    $RegexPattern = '\b(\d+)\+(\d+)\b'
    $Substitution = {
        param($Match)
    
        $Results = foreach($Amount in $Match.Groups[1,2].Value){
            $Dollars = [Math]::Floor(($Amount / 100))
            $Cents   = $Amount % 100
            '${0:0}.{1:00}' -f $Dollars,$Cents
        }
        return $Results -join '+'
    }
    

    In the scriptblock above, we expect the two capture groups ($Match.Groups[1,2]), calculate the amount of dollars and cents, and then finally use the -f string format operator to make sure that the cents value is always two digits wide.

    To do the substitution, invoke the Replace() method:

    [regex]::Replace($InputString,$RegexPattern,$Substitution)
    

    And there you go!

    Applying to to a bunch of files is as easy as:

    $RegexPattern = '\b(\d+)\+(\d+)\b'
    $Substitution = {
        param($Match)
    
        $Results = foreach($Amount in $Match.Groups[1,2].Value){
            $Dollars = [Math]::Floor(($Amount / 100))
            $Cents   = $Amount % 100
            '${0:0}.{1:00}' -f $Dollars,$Cents
        }
        return $Results -join '+'
    }
    
    foreach($file in Get-ChildItem $path *.txt){
        $Lines = Get-Content $file.FullName
        $Lines |ForEach-Object {
            [regex]::Replace($_, $RegexPattern, $Substitution)
        } |Set-Content $file.FullName
    }