![解析平面 SGF 字符串(使用 listofitems 包)](https://linux22.com/image/473536/%E8%A7%A3%E6%9E%90%E5%B9%B3%E9%9D%A2%20SGF%20%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%88%E4%BD%BF%E7%94%A8%20listofitems%20%E5%8C%85%EF%BC%89.png)
我正在尝试解析新加坡金融管理局带包装的字符串listofitems
。SGF 是文本形式的树,但目前,为了简单起见,我只研究单分支 SGF。
下面是我正在尝试做的一个例子:
\documentclass{article}
\usepackage{listofitems}
\usepackage{tikz}
\newcommand{\parseSgf}[1]{
% From [this answer by @StevenB.Segletes](https://tex.stackexchange.com/a/429895/64441).
\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
不是真正的 SGF,只是一个简单的例子。我希望它打印一个无序列表,如下所示:
- 颜色:
B
和坐标:ab
- 颜色:
W
和坐标:cd
但我一直无法弄清楚如何正确使用\setsepchar
和\defpair
分离事物,或者如何在中使用它们\foreach
。
sgfB
是一个正确的 SGF 字符串。还有一个额外的问题,就是忽略不是B
或 的键W
。如果有人知道如何用 来做到这一点listofitems
,那将是一个加分项。
答案1
我理解您主要对字符串中具有语法B[xy]
或的部分感兴趣W[xy]
(其中x
和y
是一些单个字母)。因此,下面的代码忽略了其他所有内容。
这可能不应该被视为最终版本,但也许类似的东西可以做到。在这种情况下,我使用了 expl 序列,因为大多数内容都与拆分字符串有关(请注意,如果字符串不包含任何合适的语法,可能会弹出“缺失项目”错误):
\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}
答案2
这是一种listofitems
方法。但是,它不会测试 SGF 字符串中的不正确语法,例如;B[ab[;W]cd]
,它将以与测试用例相同的方式响应\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}