【问题标题】:Format specific Lines in generated Text-File格式化生成的文本文件中的特定行
【发布时间】:2021-03-18 20:03:12
【问题描述】:

我想格式化使用 Powershell 生成的 .st(文本)文件中的特定行。

  1. 加载 TextSnippet 以供演示使用 ($TemplateSnippetText)
  2. 替换一些文本
  3. 将文本行与“:=”对齐,以便所有“:=”都在一行中(如 $TemplateSnippetText)

我正在为格式化而苦苦挣扎,可能是数学问题......? 可以使用 String.Format("{0,6} {1,15}) 方法完成吗?

期望的输出

            diMoveStep_TFRX                         := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                         := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute       := FALSE;
            diMoveStep_TFRX                         := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos1.xEnMove  THEN
                fbAxis_TFRX.i_stPar.stMove          := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition      := stDataProduct.stTFRX.lrPos_PickPos1;
                strPickPos1_TFRX                    := 'PickPos1';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute   := TRUE;
                diMoveStep_TFRX                     := 2;
            END_IF
        2:  // Bewegung ist gestartet

实际输出

        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                     := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                     := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute       := FALSE;
            diMoveStep_TFRX                     := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos1.xEnMove  THEN
                fbAxis_TFRX.i_stPar.stMove          := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition      := stDataProduct.stTFRX.lrPos_PickPos1;
                strPickPos1_TFRX                        := 'PickPos1';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute   := TRUE;
                diMoveStep_TFRX                     := 2;
            END_IF
        2:  // Bewegung ist gestartet

完整的 Powershell 5.1 代码:

$TemplateSnippetText = 
"ACTION ActAuto_Move_AXISNAME_TARGETPOS: // COMMENT
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_AXISNAME.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_AXISNAME                             := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_AXISNAME                             := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_AXISNAME OF
        0:  // Bewegung vorbereiten
            fbAxis_AXISNAME.i_stCmd.xMoveAbsolute           := FALSE;
            diMoveStep_AXISNAME                             := 1;
        1:  // Bewegung starten
            IF stPos.stAXISNAME.stTARGETPOS.xEnMove THEN
                fbAxis_AXISNAME.i_stPar.stMove              := stMovePar_AXISNAME;
                fbAxis_AXISNAME.i_stPar.lrPosition          := stDataProduct.stAXISNAME.lrPos_TARGETPOS;
                strTargetPos_AXISNAME                       := 'TARGETPOS';
                fbAxis_AXISNAME.i_stCmd.xMoveAbsolute       := TRUE;
                diMoveStep_AXISNAME                         := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_AXISNAME.q_stStat.xMoveDone AND
                stPos.stAXISNAME.stTARGETPOS.xInRange THEN
                fbAxis_AXISNAME.i_stCmd.xMoveAbsolute       := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_AXISNAME                         := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_AXISNAME.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

"
#Dateipfad
$strFilePath = 'C:\Temp\CodeSnippet.st' 
$RegPatRepWhiteSpaces = '\s+?(?=:=)'    # https://regex101.com/r/IEiymN/1
$RegPatStartOfString = '^.*?(?=:=)'     # https://regex101.com/r/icJGAy/1
$RegPatEndOfString  = ':=(.*)'          # https://regex101.com/r/0UlzT7/1


# File-Inhalt löschen
Remove-Item $strFilePath  -Include *.st

$SnippetsToGenerate = @(
    [PSCustomObject]@{COMMENT = 'Zielposition1'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos1' }
   # [PSCustomObject]@{COMMENT = 'Zielposition2'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos2' }
    #[PSCustomObject]@{COMMENT = 'Zielposition3'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos3' }
)

$SnippetsToGenerate | ForEach-Object {
$CurrentSnippet = $TemplateSnippetText
$CurrentSnippet = $CurrentSnippet -replace "COMMENT", $_.COMMENT -replace "AXISNAME", $_.AXISNAME -replace "TARGETPOS", $_.TARGETPOS
$CurrentSnippet | Out-File -FilePath $strFilePath -Append 
} 

    (Get-Content -Path $strFilePath -Raw) -Replace $RegPatRepWhiteSpaces,'' | Set-Content -Path $strFilePath
    
    $IndexOfAllocation = Get-Content -Path $strFilePath | ForEach-Object {$_.IndexOf(":=") } | Measure-Object -Maximum
    
    (Get-Content -Path $strFilePath) | ForEach-Object {
            $currentObject = $_
            if($currentObject -match ':='){   
                $StringStart = [Regex]::Matches($currentObject, $RegPatStartOfString).Value 
                $StringEnd = [Regex]::Matches($currentObject, $RegPatEndOfString ).Value

                Write-Host "Lenght StringStart" $StringStart.Length"Lenght StringEnd" $StringEnd.Length
                Write-host "Max" $IndexOfAllocation.Maximum

                [uint32]$DiffToPaddAbsolute = ($IndexOfAllocation.Maximum  - $StringStart.Length)
        
                #if (($DiffToPaddAbsolute % 4) -gt 2) {
                    $DiffToPaddAbsoluteTabs = [math]::Ceiling($DiffToPaddAbsolute / 4) + 1
                #   } else {
                    #$DiffToPaddAbsoluteTabs = [math]::Floor($DiffToPaddAbsolute / 4) + 1
                #}
                $StringStartPadded= $StringStart.PadRight($StringStart.Length + $DiffToPaddAbsoluteTabs,[char]9)
                $currentObject = "$StringStartPadded$StringEnd"
                }
            $currentObject
    } | Set-Content  -Path $strFilePath
Invoke-Item $strFilePath

【问题讨论】:

  • 如果您提供示例输入和所需输出,我们会帮助您。

标签: powershell string-formatting


【解决方案1】:

我认为您可能使填充过于复杂-根本不需要正则表达式,我们只需要在初始替换后的每一行中找到:= 出现的偏移

$FilePath = "C:\Temp\CodeSnippet.st"
$TemplateSnippetText = "<Insert Your Template Here>"

$SnippetsToGenerate = @(
  [PSCustomObject]@{COMMENT = 'Zielposition1'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos1' }
  [PSCustomObject]@{COMMENT = 'Zielposition2'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos2' }
  [PSCustomObject]@{COMMENT = 'Zielposition3'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos3' }
)

$SnippetsToGenerate | ForEach-Object {
  # Use `-creplace` (Case-sensitive replace)
  $snippet = $TemplateSnippetText -creplace 'COMMENT', $_.COMMENT -creplace 'AXISNAME', $_.AXISNAME -creplace 'TARGETPOS', $_.TARGETPOS

  # Split into individual lines
  $lines = $snippet -split '\r?\n'
  
  # Use String.IndexOf() to find the current column offset of `:=` in each line
  $offsets = $lines | ForEach-Object IndexOf ':='
  
  # Sort the offsets to find the right-most occurrence (we will align everything to this one)
  $targetOffset = $offsets | Sort-Object -Descending | Select-Object -First 1
  
  for ($i = 0; $i -lt $lines.Count; $i++) {
    $line = $lines[$i]
    $offset = $offsets[$i]
  
    if ($offset -in 0..$targetOffset) {
      # $offset is > -1, so we know the line contains a `:=`, let's left-pad it by 
      # inserting the required number of spaces at the position right in front of `:=`
      $lines[$i] = $line.Insert($offset, [string]::new(" ", $targetOffset - $offset))
    }
  }

  # Output 
  $lines
} |Set-Content $FilePath

使用您问题中提供的模板,在CodeSnippet.st 中为我提供了以下输出:

ACTION ActAuto_Move_TFRX_PickPos1: // Zielposition1
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                                 := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                                 := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute               := FALSE;
            diMoveStep_TFRX                                 := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos1.xEnMove THEN
                fbAxis_TFRX.i_stPar.stMove                  := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition              := stDataProduct.stTFRX.lrPos_PickPos1;
                strTargetPos_TFRX                           := 'PickPos1';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := TRUE;
                diMoveStep_TFRX                             := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_TFRX.q_stStat.xMoveDone AND
                stPos.stTFRX.stPickPos1.xInRange THEN
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_TFRX                             := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_TFRX.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

ACTION ActAuto_Move_TFRX_PickPos2: // Zielposition2
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                                 := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                                 := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute               := FALSE;
            diMoveStep_TFRX                                 := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos2.xEnMove THEN
                fbAxis_TFRX.i_stPar.stMove                  := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition              := stDataProduct.stTFRX.lrPos_PickPos2;
                strTargetPos_TFRX                           := 'PickPos2';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := TRUE;
                diMoveStep_TFRX                             := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_TFRX.q_stStat.xMoveDone AND
                stPos.stTFRX.stPickPos2.xInRange THEN
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_TFRX                             := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_TFRX.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

ACTION ActAuto_Move_TFRX_PickPos3: // Zielposition3
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                                 := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                                 := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute               := FALSE;
            diMoveStep_TFRX                                 := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos3.xEnMove THEN
                fbAxis_TFRX.i_stPar.stMove                  := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition              := stDataProduct.stTFRX.lrPos_PickPos3;
                strTargetPos_TFRX                           := 'PickPos3';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := TRUE;
                diMoveStep_TFRX                             := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_TFRX.q_stStat.xMoveDone AND
                stPos.stTFRX.stPickPos3.xInRange THEN
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_TFRX                             := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_TFRX.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

如果要保留原始偏移量,只需根据模板计算$targetOffset而不进行任何替换,生成实际的sn-ps之前:

$targetOffset = $TemplateSnippetText -replace '\r?\n' |ForEach-Object IndexOf := |Sort-Object -Descending |Select-Object -First 1

$SnippetsToGenerate | ForEach-Object {
   # ...

【讨论】:

  • 类似的东西是我的第一个方法。但是结构化文本文件似乎是具有另一种编码的文件。 \t 4 \s。我该如何处理? Sample.
  • @Txitxarro 恐怕我不明白你的意思,你可以update your question 提供样本吗?
  • VS 代码设置:渲染空白选择是«全部»。如果我在 VSC 中打开最初使用 «b&r 自动化工作室»创建的 .st 文件,则选项卡不是 4 个空格,而是 ''-> '' 变量 $TemplateSnippetText 中的字符串,我最初是从 .st 文件中复制的Powershell-File 也带有 -> (\t) 但是您的解决方案中的字符串仅带有空格。但无论如何,将以下内容添加到您的解决方案中:# Output $lines -replace " ", [char]9 -replace ' +?(?=:=)' , '' 非常感谢。我将在星期一对其进行全面测试并给您反馈
  • @Txitxarro 啊,这是有道理的。很高兴听到你把它整理出来,不客气! :-)
【解决方案2】:

再次感谢 Mathias 帮助我解决这个问题。不得不改变一些东西:

$FilePath = "C:\Temp\CodeSnippet.st"
$RegPatRepWhiteSpaces = '\s+?(?=:=)'    # https://regex101.com/r/IEiymN/1
[uint16]$SpacesPerTab = 4
$SpacesPerTabAsString = [string]::new([char]32, $SpacesPerTab)
$TemplateSnippetText = 
"
ACTION Svd_NAME : // Schutzverdeck: COMMENT
    stHw.stBasic.stSvd_AXISNAME.stIn.xProtCircleIsClosedAndLocked   := xReplaceMe;
    stHw.stBasic.stSvd_AXISNAME.stIn.xAreaRdyForSvd             := xRepalaceMe;
    fbSvd_AXISNAME.i_stIoMap                                    := stHw.stBasic.stSvd_AXISNAME.stIn; 
    fbSvd_AXISNAME.i_udiVisu                                        := ADR(stVisu.stBasic.stSvd_AXISNAME); 
    fbSvd_AXISNAME();
    stHw.stBasic.stSvd_AXISNAMEstOut                        := fbSvd_AXISNAME.q_stIoMap;
    xReplaceMe                                                      := fbSvd_AXISNAME.q_stStat.xRequest;
END_ACTION
"

$SnippetsToGenerate = @(
  [PSCustomObject]@{COMMENT = 'ZielpositionMitEinerLaenge'; AXISNAME = 'LangeraAcnName'; TARGETPOS = 'PickPos1' }
  [PSCustomObject]@{COMMENT = 'Zielposition2'; AXISNAME = 'EinNochViiisiiiiiiiiiiiiiielLaengereAchsenName'; TARGETPOS = 'PickPos2' }
  [PSCustomObject]@{COMMENT = 'Zielposidaassdtion3'; AXISNAME = 'TFRaaassdX'; TARGETPOS = 'PicdkPos3' }
)

$SnippetsToGenerate | ForEach-Object {
  # Use `-creplace` (Case-sensitive replace)
  $snippet = $TemplateSnippetText -creplace 'COMMENT', $_.COMMENT -creplace 'AXISNAME', $_.AXISNAME -creplace 'TARGETPOS', $_.TARGETPOS 

  # Replace all Tabs with Spaces to keep calculation simple
  $snippet =  $snippet -replace [char]9, $SpacesPerTabAsString -replace $RegPatRepWhiteSpaces, ''

  # Split into individual lines
  $lines = $snippet -split '\r?\n'
  
  # Use String.IndexOf() to find the current column offset of `:=` in each line
  $offsets = $lines | ForEach-Object IndexOf ':='
  
  # Sort the offsets to find the right-most occurrence (we will align everything to this one)
  $targetOffset = $offsets | Sort-Object -Descending | Select-Object -First 1

  # Round the offset to the next number divisible by SpacesPerTab, then add one more tab
  $targetOffset += ($targetOffset % $SpacesPerTab) + $SpacesPerTab

  for ($i = 0; $i -lt $lines.Count; $i++) {
    $line = $lines[$i]
    $offset = $offsets[$i]

    # $offset is > -1, so we know the line contains a `:=`
    if ($offset -in 0..$targetOffset) {

        # Calculate the number of Spaces that we want to insert
        $SpacesToInsert = ($targetOffset - $offset) % $SpacesPerTab

        # Calculate the number of Tabs that we want to insert (after filling with Spaces)
        $TabsToInsert = ($targetOffset - $offset - $SpacesToInsert) / $SpacesPerTab

        # First inserting the required number of spaces at the position right in front of `:=` and after fill up with Tabs
        $lines[$i] = $line.Insert($offset, [string]::new(" ", $SpacesToInsert)).Insert($offset + $SpacesToInsert, [string]::new([char]9, $TabsToInsert ))
      }
  }
  # Output, Replace all Groups of Spaces with Tabs
  $lines -replace  $SpacesPerTabAsString, [char]9  
} |Set-Content $FilePath

Invoke-Item "C:\Temp\CodeSnippet.st"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 2016-03-05
    相关资源
    最近更新 更多