如何读取一行到特定点然后添加新行
How to read a line to a specific point and then add a new line
我正在尝试制作一个文件解析器,它将获取一个原始输入文件,然后创建一个新文件,该文件的所有元素都按正确的顺序排列,并带有适当的换行符,以便另一个解析器可以读取它。
所以我的文件是 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
-------------------------------
在 Reddit 的 /r/chess 上,你可以用 [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]
感谢任何帮助!
嗨呀,
编辑:这是不正确的,因为我不知道 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]
这是将您的 PGN 转换为 Reddit-compatible 格式的函数。请注意,目前它不支持每个文件包含多个游戏的 PGN。
使用此功能,您可以:
- 选择 "headers" 要保留的内容。默认情况下仅保留
Event
、Date
、White
、Black
和 Result
- 将新的 PGN 保存到文件或输出到管道
函数接受以下参数:
- 路径: 原始 PNG 文件的路径
- OutFile: 转换后的 PGN 文件的路径
- KeepHeaders:要保留的 "headers" 列表
使用示例:
转换文件,输出到屏幕
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
转换文件,输出到屏幕,只保留BlackElo
和Time
headers
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
}
}
}
我正在尝试制作一个文件解析器,它将获取一个原始输入文件,然后创建一个新文件,该文件的所有元素都按正确的顺序排列,并带有适当的换行符,以便另一个解析器可以读取它。
所以我的文件是 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
-------------------------------
在 Reddit 的 /r/chess 上,你可以用 [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]
感谢任何帮助!
嗨呀,
编辑:这是不正确的,因为我不知道 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]
这是将您的 PGN 转换为 Reddit-compatible 格式的函数。请注意,目前它不支持每个文件包含多个游戏的 PGN。
使用此功能,您可以:
- 选择 "headers" 要保留的内容。默认情况下仅保留
Event
、Date
、White
、Black
和Result
- 将新的 PGN 保存到文件或输出到管道
函数接受以下参数:
- 路径: 原始 PNG 文件的路径
- OutFile: 转换后的 PGN 文件的路径
- KeepHeaders:要保留的 "headers" 列表
使用示例:
转换文件,输出到屏幕
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
转换文件,输出到屏幕,只保留
BlackElo
和Time
headersConvertPgn-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
}
}
}