Hi,
has anybody created a plugin or something with chess-related functions? In particular I am interested in a parser for PGN chess files. There are plenty of them in other languages, so I wonder if anybody attempted to write one in Xojo.
About the char by char I did not want to mean that I want to read char by char from the text file. My idea was to read N bytes at time, put them in a MemoryBlock and access it byte by byte (alas char by char). What is not clear to me is: should I convert each byte to string? should I care about big/little endian for cross-platform compatibility? what about encoding? how to handles bytes which belong to two different blocks (given that I read N bytes at time)? should I “consume” the read bytes?
That standard calls for ASCII files, so encoding will not be an issue. You can put the whole thing in a MemoryBlock and go byte-by-byte if you want, or use a regular expression to pull out each new move.
FYI, big/little endian only applies to integers or doubles, never strings. Strings are always left to right.
“Usually, the PGN contains one entire game, but it can also record just a fraction of a game.”
Thats not likely to be an enormous file.
Its not a very robust file format… comments can occur anywhere and have a number of indicators
Moves are recorded in algebraic notation, and comments can be inserted after a “;” symbol or between parentheses or curly brackets.
Its probably quite old… JSON or XML would meet these needs so much better by keeping data types separate… comments would be an optional attribute of a move, for example.
Trying to brute force this file needs you to look for successive numbers followed by a dot, to indicate move groupings.
etc
Inside which you get 2 algebraic notations, which MIGHT be side by side.
Rd1 Qe6
or MIGHT have a comment in the middle
Rd1 {Woah… this is a bad move!} Qe6
or at the end
Rd1 Qe6 ; Another comment.
Since the comment could contain numbers, dots, or semicolons… yikes…
So while it is certainly possible to read the file from left to right, careless comments could easily cause you problems.
I tried your regex with the following file (a valid pgn file with just one game), using the code below, but it does not work. Am I missing something?
Thank you,
Davide.
Code:
Var f As FolderItem = FolderItem.ShowOpenFileDialog("PGN")
If f <> Nil Then
If f.Exists Then
Var t As TextInputStream
Try
t = TextInputStream.Open(f)
t.Encoding = Encodings.MacRoman
Var pgnData As String = t.ReadAll
Var rg As New RegEx
Var myMatch As RegExMatch
rg.SearchPattern = "(?x)(?-i)(?(DEFINE)(?<PC>[RBNKQ])(?<GRID>[a-h])(?<SQ>(?&GRID)[1-8])(?<CSTL>O-O(?:-O)?)(?<PCMV>(?&PC)?(?&GRID)?x?(?&PC)?(?&SQ)[+#]?)(?<MV>(?&CSTL)|(?&PCMV))(?<CMT>\( [^)]* \) |\{ [^}]* \} |; .*))\b(\d+) \. \s*((?&CMT))?((?&MV))\s*(?:((?&CMT)) \s*)?(?:((?&MV))\s*((?&CMT))?)?"
myMatch = rg.Search(pgnData)
If myMatch <> Nil Then
MessageBox(myMatch.SubExpressionString(0))
Else
MessageBox("text not found")
End If
Exception err As RegExException
MessageBox(err.Message)
Catch e As IOException
MessageBox("Error accessing file.")
End Try
t.Close
End If
End If
It’s an additional annotation, and may appear, I guess, anywhere, just like a comment. Unfortunately, I don’t have time to update the pattern to account for this, or other things I missed (like “=”), put perhaps you want to tackle it.
FYI, you could have used my pattern as-is through a class or module constant rather than stripping the linefeeds and comments. It makes it easier to read and modify.
Were the docs always that thin? I can’t find an example.
You need to loop through the matches:
dim theRegex as new RegEx
theRegex.options.greedy = False
theRegex.Options.DotMatchAll = True
theRegex.searchPattern = EscapeRegex(Boundary) + "(.+)(\n\n|\r\r)"
dim theRegexMatch as RegExMatch = theRegex.search(MessageRawData)
dim theText(-1) as String
dim Starts(-1) as Integer
dim theStart as Integer
while theRegexMatch <> nil
if theRegexMatch.SubExpressionCount < 2 then Continue
theStart = theRegexMatch.subExpressionStartB(0) + theRegexMatch.subExpressionString(0).Length
Starts.add(theStart)
theText.Add theRegexMatch.SubExpressionString(1)
theRegex.SearchStartPosition = theStart
theRegexMatch = theRegex.search()
Wend