2

I'm trying to parse an SGF string with the package listofitems. SGFs are trees in text form, but right now, I'm working on only single-branched SGFs, for simplicity.

Here's an example of what I'm trying to do:

\documentclass{article}

\usepackage{listofitems} \usepackage{tikz}

\newcommand{\parseSgf}[1]{ % From this answer by @StevenB.Segletes. \setsepchar{;} \defpair{[]}

\readlist\Z{#1}

\begin{itemize} \foreach \i in {\Z}{ % TODO: if key is either B or W: \item Color: {\i}[0] and Coords: {\i}[1] } \end{itemize} }

\begin{document} \def\sgfA{;B[ab];W[cd]} \def\sgfB{(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[6.5]SZ[19]DT[2024-02-05];B[as];W[bs];B[cs])}

\parseSgf{\sgfA} \parseSgf{\sgfB} \end{document}

sgfA isn't proper SGF, just a simple example. I would like it to print an unordered list like this:

  • Color: B and Coords: ab
  • Color: W and Coords: cd

But I haven't been able to figure out how to use \setsepchar and \defpair to separate things properly, or how to use them in a \foreach.

sgfB is a proper SGF string. And there's the additional problem of ignoring keys that are not B or W. If anyone knows how to do it with listofitems, that would be a plus.

psygo
  • 438
  • You really should not use \foreach for this. It is especially created for TikZ/PGF and does several things such as scoping and expanding that you will find annoying when used in another context. Why not stick to the functions provided by the listofitems package? – Jasper Habicht Feb 07 '24 at 14:45
  • SGF seems to have a quite complicated syntax. So, I am unsure whether this can be simply parsed using some loops. But maybe, it can. You probably know that there exists a tool sgf2dg written in Perl that seems to allow to translate SGF to diagrams also in TeX format. – Jasper Habicht Feb 07 '24 at 14:52
  • Oh. I actually didn't know about sgf2dg. Does it generate TeX code or EPS pictures? I only knew about the ancient psgo and igo packages, and that's why I'm trying to create a new package, because those are too old, and difficult to work with (also, I'm trying to learn more about TeX). In the past, I used to generate EPS diagrams through GoWrite2. – psygo Feb 07 '24 at 15:08
  • I don't know anything about sgf2dg. I just stumbled upon it when looking for more infomration about the SGF syntax. – Jasper Habicht Feb 07 '24 at 15:12
  • 1
    The SGF editor Sabaki is open source. And its SGF parser is here (I also have my own sort of working version here). Maybe that could be useful. But I think, for this question, just splitting around ; and key[value] should be enough. – psygo Feb 07 '24 at 15:19
  • Maybe then it would be enough to first split at ; and then at [ (and at ] or just delete ]). Are you bound to the listofitems package? – Jasper Habicht Feb 07 '24 at 15:53
  • No, I'm not bound to listofitems. It just seemed very handy. – psygo Feb 07 '24 at 16:34
  • For \sgfB, what should the output look like? – Steven B. Segletes Feb 07 '24 at 17:18
  • @StevenB.Segletes For \sgfB, these are the moves: ;B[as];W[bs];B[cs], the beginning is game metadata. So the output should be a this formatted as a list: Color: B and Coords: as, Color: W and Coords: bs, and Color: B and Coords: cs. – psygo Feb 07 '24 at 17:30
  • @StevenB.Segletes please do create a tag for your awesome listofitems package if you're able to. This way I can tag it here. – psygo Feb 07 '24 at 17:34
  • I have to depart for a couple of hours, but will have a further look. One question: how am I to know, via parsing, that ;GM[1]... is not part of a color/coords specification? – Steven B. Segletes Feb 07 '24 at 17:47
  • 1
    @StevenB.Segletes Because its key is GM, not B or W. All the fields are of the shape key[value]. Moves are represented by the keys B (Black) and W (White). There are plenty other "official" keys in the SGF specification (the grammar actually doesn't disallow any key actually), but those are the two most important ones. – psygo Feb 07 '24 at 17:52

2 Answers2

2

I undestand that you are primarily interested in the parts of the string which have the syntax B[xy] or W[xy] (where x and y are some single letters). The below code therefore ignores everything else.

This should probably not be considered the final version, but maybe something like this can do. I used expl sequences in this case as most of the things are related to splitting strings (note that a "missing item" error may pop up, if the string does not contain any suitable syntax):

\documentclass{article}

\ExplSyntaxOn \cs_generate_variant:Nn \tl_set:Nn { Ne } % You might need to add this if the version of your TeX installation is not the most recent one \cs_generate_variant:Nn \seq_set_split:Nnn { Nne } \NewDocumentCommand{\parseSgf}{ m }{ \tl_set:Ne \l_tmpa_tl { #1 } % remove ( and ) from string \tl_remove_all:Nn \l_tmpa_tl { ( } \tl_remove_all:Nn \l_tmpa_tl { ) } % store the contents of #1 in a sequence with ; as delimiter \seq_set_split:Nne \l_tmpa_seq { ; } { \l_tmpa_tl } \begin{itemize} % loop over all items in sequence \seq_map_inline:Nn \l_tmpa_seq { % split string at [ and store result in another sequence \seq_set_split:Nne \l_tmpb_seq { [ } { ##1 } \bool_if:nT { % test if first part of sequence is B or W \str_if_eq_p:ee { \seq_item:Nn \l_tmpb_seq { 1 } } { B } || \str_if_eq_p:ee { \seq_item:Nn \l_tmpb_seq { 1 } } { W } } { \tl_set:Ne \l_tmpa_tl { \seq_item:Nn \l_tmpb_seq { 1 } } \tl_set:Ne \l_tmpb_tl { \seq_item:Nn \l_tmpb_seq { 2 } } % remove ] from string \tl_remove_all:Nn \l_tmpb_tl { ] } \item Color: ~ \l_tmpa_tl {} ~ and ~ Coords: ~ \l_tmpb_tl } } \end{itemize} } \ExplSyntaxOff

\begin{document}

\def\sgfA{;B[ab];W[cd]} \def\sgfB{(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[6.5]SZ[19]DT[2024-02-05];B[as];W[bs];B[cs])}

\parseSgf{\sgfA} \parseSgf{\sgfB}

\end{document}

enter image description here

  • Strange, on LaTeX Worksho on VS Code, I'm getting Undefined control sequence. \parseSgf code #1->\tl_set:Ne for this piece of code. @JasperHabicht, do you know what that is? – psygo Feb 07 '24 at 17:58
  • 1
    Maybe the installation is not new enough. Add \cs_generate_variant:Nn \tl_set:Nn { Ne } right after \ExplSyntaxOn. This should solve the issue. – Jasper Habicht Feb 07 '24 at 18:05
  • True, that does solve the issue. My tex -v output says: TeX 3.141592653 (TeX Live 2023) (I think I installed it on my M2 Mac 2023 last October). Is that outdated already? – psygo Feb 07 '24 at 18:09
  • 1
    @PhilippeFanaro I am not sure. But it does not really matter, yours is surely new enough. Expl3 is updated quite often, as far as I know. Altough being stable, some code is added every now and then. Maybe this part was added very recently. – Jasper Habicht Feb 07 '24 at 18:15
  • I'm trying to adapt your answer to my drawing of moves code. More specifically, instead of itemize stuff, I would also replace Color: ~ \l_tmpa_tl {} ~ and ~ Coords: ~ \l_tmpb_tl with something like \drawStoneFromSgfCoords{black}{\l_tmpb_tl}. But I'm getting Argument of \use_i:nn has an extra }. Do you know why? – psygo Feb 08 '24 at 13:22
  • @PhilippeFanaro Try \exp_args:Nee \drawStoneFromSgfCoords {black} {\l_tmpb_tl} which first expands the arguments before executing the function. – Jasper Habicht Feb 08 '24 at 14:57
2

Here is a listofitems approach. However, it will not test for improper syntax in the SGF string, such as ;B[ab[;W]cd], which will respond in the same way as the test case \sgfA.

\documentclass{article}
\usepackage{listofitems,tikz}
\long\def\Firstof#1#2\endFirstof{#1}
\ignoreemptyitems
\newcommand{\parseSgf}[1]{%
  \setsepchar{;/[||]}%
  \readlist*\Z{#1}%
  \begin{itemize}
    \foreachitem \i \in \Z[]{%
      \itemtomacro\Z[\icnt,1]\tmp
      % TODO: if key is either `B` or `W`:
      \expandafter\if\expandafter\Firstof\tmp\endFirstof B
        \item Color: \tmp and Coords: \Z[\icnt,2]
      \else\expandafter\if\expandafter\Firstof\tmp\endFirstof W
        \item Color: \tmp and Coords: \Z[\icnt,2]
      \fi\fi
    }%
  \end{itemize}
}
\begin{document}
  \def\sgfA{;B[ab];W[cd]}
  \def\sgfB{(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[6.5]SZ[19]DT[2024-02-05];B[as];W[bs];B[cs])}
  \parseSgf{\sgfA}\bigskip
  \parseSgf{\sgfB}
\end{document}

enter image description here