如何读取特定点的行,然后添加新行

时间:2015-10-28 18:55:17

标签: powershell powershell-v2.0 powershell-v3.0

我正在尝试创建一个文件解析器,它将获取一个原始输入文件,然后创建一个新文件,其中包含正确顺序的所有元素,并使用适当的新行,以便另一个解析器可以读取它。

所以我的文件是PGN(Portable Games Notation)。这些文件用于国际象棋以记录人们在计算机上玩的游戏。

他们看起来像:

--------------------------------------
[Event "Computer chess game"]
[Date "2015.10.28"]
[Round "?"]
[White "White Player"]
[Black "Black Player"]
[Result "1-0"]
[BlackElo "2400"]
[ECO "A25"]
[Opening "English"]
[Time "10:39:20"]
[Variation "Closed"]
[WhiteElo "2400"]
[Termination "normal"]
[PlyCount "63"]
[WhiteType "human"]
[BlackType "human"]
1. f3 e6 2. g4 Qh4# 1-0
-------------------------------

在Reddit的/ r /象棋上,他们可以使用[pgn][/pgn]将游戏包围起来,然后它会创建一个可玩的棋盘,让您或其他人可以逐步完成您的游戏并为您提供建议等。

问题是我玩的网站,PGN如上所述。 / r / chess解析器不喜欢它。

它更倾向于将每一个动作分开:

1. f3 e6 
2. g4 Qh4# 1-0

由于我正在尝试学习Powershell,我想创建一个可以打开原始PGN的脚本,然后将其重新格式化为如上所示,并可能拉出事件,日期,白人播放器,黑人播放器和结果。然后对其进行格式化,以便在每次移动后插入一个新行。然后输出一个用[pgn][/pgn]包围的新文件。

我很失落如何做到这一点。我需要使用正则表达式吗?我知道,一旦我将文件读入Powershell,我就可以像对待数组那样对待它。

输出文件应如下所示:

[pgn][Event "Computer chess game"]
[Date "2015.10.28"]
[White "White Player"]
[Black "Black Player"]
[Result "1-0"]
1. f3 e6 
2. g4 Qh4# 1-0 [/pgn]

感谢任何和所有帮助!

2 个答案:

答案 0 :(得分:2)

这是将PGN转换为Reddit兼容格式的函数。请注意,目前它不支持每个文件有多个游戏的PGN。

使用此功能,您可以:

  • 选择"标题"保持。默认情况下,仅保留EventDateWhiteBlackResult
  • 将新PGN保存到文件或输出到管道

函数接受以下参数:

  • 路径原始PNG文件的路径
  • OutFile 已转换的PGN文件的路径
  • KeepHeaders "标题列表"保持

用法示例:

  • 转换文件,输出到屏幕

    ConvertPgn-ForReddit -Path .\Foo.pgn
    
    [pgn]
    [Event "Computer chess game"]
    [Date "2015.10.28"]
    [White "White Player"]
    [Black "Black Player"]
    [Result "1-0"]
    1. f3 e6 
    2. g4 Qh4# 1-0
    [/pgn]
    
  • 转换文件,输出到文件

    ConvertPgn-ForReddit -Path .\Foo.pgn -OutFile .\Bar.pgn
    
  • 转换文件,输出到屏幕,仅保留BlackEloTime标题

    ConvertPgn-ForReddit -Path .\Foo.pgn -KeepHeaders BlackElo, Time
    
    [pgn]
    [BlackElo "2400"]
    [Time "10:39:20"]
    1. f3 e6 
    2. g4 Qh4# 1-0
    [/pgn]
    

代码:

function ConvertPgn-ForReddit
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateScript({
            Test-Path $_
        })]
        [ValidateNotNullOrEmpty()]
        [string]$Path,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]$OutFile,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string[]]$KeepHeaders = @('Event', 'Date', 'White', 'Black', 'Result')
    )

    Process
    {
        # Get file contents as array of strings
        $PgnFile = Get-Content -Path $Path 

        # Get all "headers", e.g. [Event "Computer chess game"]
        $Headers = $PgnFile | Where-Object {$_ -match '\[.*\]'}

        # Filter "headers", so they contain only the ones we want
        $FilteredHeaders = $KeepHeaders | ForEach-Object {
            $currHeader = $_
            $Headers | Where-Object {$_ -match  "\[$currHeader\s+.*\]"}
        }

        # Get chess moves
        $Moves = $PgnFile | Where-Object {$_ -match '^\d+\.'}
        # Split them, remove empty lines if any
        $SplittedMoves = $Moves | ForEach-Object {$_ -split '(\d+\.)'} | Where-Object {$_}
        # Join splitted chess moves: delimeter + actual move. E.g. "1." +  "f3 e6 "
        $JoinedMoves = 0..($SplittedMoves.Count - 1) | ForEach-Object {
            if([bool]!($_ % 2))
            {
                '{0} {1}' -f $SplittedMoves[$_], $SplittedMoves[$_+1]
            }
        }

        # Create PGN in Reddit-compatible format
        $RedditPgn = '[pgn]', $FilteredHeaders, $JoinedMoves, '[/pgn]'

        if($OutFile)
        {
            # If OutFile is specified, save it
            $RedditPgn | Set-Content -Path $OutFile
        }
        else
        {
            # If not - just output to the pipeline
            $RedditPgn
        }
    }
}

答案 1 :(得分:-1)

Heyya,

编辑:这不正确,因为我不知道PGN是如何工作的......

这是我的尝试。输入文件pgn.txt,输出文件converted_pgn.txt。根据您提供的样品。如果您更改输入文件中的行数或它们的顺序,则会将其分解为多个部分:)。

Get-Content将从提供的输入文件中生成array。然后你只需保留你想要的细胞。

为了分开这些动作,我去了Split空格。

所有这一切都没有真正完善,你可以用正则表达式做更好的工作,如果一切都要改变,输入方式。

#$pgn = Get-Content "pgn.txt"
#this will give us an array like below

$pgn = "--------------------------------------",
"[Event `"Computer chess game`"]",
"[Date `"2015.10.28`"]",
"[Round `"?`"]",
"[White `"White Player`"]",
"[Black `"Black Player`"]",
"[Result `"1-0`"]",
"[BlackElo `"2400`"]",
"[ECO `"A25`"]",
"[Opening `"English`"]",
"[Time `"10:39:20`"]",
"[Variation `"Closed`"]",
"[WhiteElo `"2400`"]",
"[Termination `"normal`"]",
"[PlyCount `"63`"]",
"[WhiteType `"human`"]",
"[BlackType `"human`"]",
"1. f3 e6 2. g4 Qh4# 1-0",
"-------------------------------"

$moves = $pgn[17].Split(" ")

$m1 = $moves[0] + " " + $moves[1] + " " + $moves[2]

$m2 = $moves[3] + " " + $moves[4] + " " + $moves[5] + " " + $moves[6]

"[pgn]$($pgn[1])",$pgn[2],$pgn[4],$pgn[5],$pgn[6],$m1,"$m2 [/pgn]" | Out-File "converted_pgn.txt"

输出:

[pgn][Event "Computer chess game"]
[Date "2015.10.28"]
[White "White Player"]
[Black "Black Player"]
[Result "1-0"]
1. f3 e6
2. g4 Qh4# 1-0 [/pgn]