powershellpowershell-workflow

Format change not working if there is small change in input


I have a file with below content, i wanted to convert all the build jobs into a different format like in expected output.

parallel
(
{
    build( "job2", parameter3: value3, parameter4: value4, parameter5: value5 )
    build( "job1", parameter1: value1, parameter2: value2 )
)
}
parallel 
(
{
    build( "job3", parameter6: value6, parameter7: value7, parameter8: value8,  parameter9: value9 )
}
)

build( "jobx", parameterx: valuex, parameterx: valuex, parameterx: valuex,  parameterx: valuex )

build( "jobxx", parameterxx: valuexx, parameterxx: valuexx, parameterx: valuex,  parameterx: valuex )

build("jobxy", parameterxy: "https://abc-xyz.pqrs.com", parameterxy: valuexy, parameterxy: valuexy)

I am able to convert most of them with Santiago Squarzon code [link:https://stackoverflow.com/questions/76717578/loop-through-each-line-of-a-text-file-split-and-get-the-required-values-and-use#comment135289657_76717709] but not able to convert if one single job has any url in " ".

I have tried below and output is this

$teststrings = Get-Content path\to\file.txt

$re = [regex]::new(
    '(?<=build\()\s*"(?<jobname>[^""]+)"(?:,\s*(?<paramname>\w+)\s*:\s*(?<paramvalue>\w+))+',
    [System.Text.RegularExpressions.RegexOptions] 'Compiled, IgnoreCase')

foreach ($string in $teststrings) {
    $match = $re.Match($string)

    if (-not $match.Success) {
        continue
    }

    $params = @($match.Groups['paramname'].Captures.Value)
    $values = @($match.Groups['paramvalue'].Captures.Value)

    $groups = for ($i = 0; $i -lt $params.Count; $i++) {
        "string(name: '{0}', value: ""`${{{1}}}"")" -f $params[$i], $values[$i]
    }

    "build job: '{0}', parameters: [{1}]" -f $match.Groups['jobname'].Value, ($groups -join ', ')
}

Output which I got

build job: 'job2', parameters: [string(name: 'parameter3', value: "${value3}"), string(name: 'parameter4', value: "${value4}"), string(name: 'parameter5', value: "${value5}")]
build job: 'job1', parameters: [string(name: 'parameter1', value: "${value1}"), string(name: 'parameter2', value: "${value2}")]
build job: 'job3', parameters: [string(name: 'parameter6', value: "${value6}"), string(name: 'parameter7', value: "${value7}"), string(name: 'parameter8', value: "${value8}"), string(name: 'parameter9', value: "${value9}")]
build job: 'jobx', parameters: [string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}")]
build job: 'jobxx', parameters: [string(name: 'parameterxx', value: "${valuexx}"), string(name: 'parameterxx', value: "${valuexx}"), string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}")]

output for the last one was skipped.

My expected out put is

build job: 'job2', parameters: [string(name: 'parameter3', value: "${value3}"), string(name: 'parameter4', value: "${value4}"), string(name: 'parameter5', value: "${value5}")]
build job: 'job1', parameters: [string(name: 'parameter1', value: "${value1}"), string(name: 'parameter2', value: "${value2}")]
build job: 'job3', parameters: [string(name: 'parameter6', value: "${value6}"), string(name: 'parameter7', value: "${value7}"), string(name: 'parameter8', value: "${value8}"), string(name: 'parameter9', value: "${value9}")]
build job: 'jobx', parameters: [string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}")]
build job: 'jobxx', parameters: [string(name: 'parameterxx', value: "${valuexx}"), string(name: 'parameterxx', value: "${valuexx}"), string(name: 'parameterx', value: "${valuex}"), string(name: 'parameterx', value: "${valuex}")]

build job: 'jobxy', parameters: [string(name: 'parameterxy', value: "https://abc-xyz.pqrs.com"), string(name: 'parameterxy', value: "${valuexy}"), string(name: 'parameterxy', value: "${valuexy}")

Solution

  • Assuming the URLs are always in between "..." then the following might work for you:

    $teststrings = Get-Content path\to\file.ext
    
    $re = [regex]::new(
        '(?<=build\()\s*"(?<jobname>[^"]+)"(?:,\s*(?<paramname>\w+)\s*:\s*(?<paramvalue>\w+|".+"))+',
        [System.Text.RegularExpressions.RegexOptions] 'Compiled, IgnoreCase')
    
    foreach ($string in $teststrings) {
        $match = $re.Match($string)
    
        if (-not $match.Success) {
            continue
        }
    
        $params = @($match.Groups['paramname'].Captures.Value)
        $values = @($match.Groups['paramvalue'].Captures.Value)
    
        $groups = for ($i = 0; $i -lt $params.Count; $i++) {
            if ($values[$i].StartsWith('"')) {
                "string(name: '{0}', value: {1})" -f $params[$i], $values[$i]
                continue
            }
            "string(name: '{0}', value: ""`${{{1}}}"")" -f $params[$i], $values[$i]
        }
    
        "build job: '{0}', parameters: [{1}]" -f $match.Groups['jobname'].Value, ($groups -join ', ')
    }
    

    For regex details see: https://regex101.com/r/J6jDpm/1.

    The only thing changing from previous code is the capturing group (?<paramvalue>\w+) changed to (?<paramvalue>\w+|".+") and the addition of an if in the for loop which checks if the captured string starts with " and if it does then it will output it as-is (without wrapping the string in between ${...}).