递归字符串解析

递归字符串解析

我一直在编写一个 LaTeX 递归流处理器,将一组常用命令的简写版本转换为更长的形式。下面的代码代表了我在意识到 xstrings 不允许嵌套宏之前所做的工作。

该程序应该执行以下操作:

  • 检查输入的长度是否为 0。
  • 否则它会检查第一组中是否有任何命令(目前只有旋转)
  • 否则,它会检查第二组中是否有任何命令(其中 flip 是)
  • 否则它只返回符号

如果它找到一个符号,它会嵌套并使用输入流中的剩余字符进行递归调用,否则它只是将递归调用附加到当前字符。

我想保留程序的递归性质,因为这是最合乎逻辑的,因为有可能出现嵌套的情况

\newcommand{\processSymbol}[1]{
    \IfEq{0}{\StrLen{#1}}{}{\CheckRotate{\firstChar{#1}}{\restChars{#1}}}
}

\newcommand{\AECheckRotate}[2]{
    \begin{switch}{#1} 
        \case{c}{\AEccwRotate{\processSymbol{#2}}}
        \AECheckFlip{#1}{#2}
    \end{switch}
}
\newcommand{\AECheckFlip}[2]{
    \begin{switch}
        \case{v}{\flipv{\processSymbol{#2}}}
        #1\processSymbol{#2}
    \end{switch}
}

尽管命令集是任意的,但我编写的示例代码的示例输入将是这样的:

vccb

在我的完整代码中应该返回如下内容:

P

因为它会旋转、旋转并垂直翻转字母 b。

我正在尝试找出另一种方法以这种方式进行嵌套字符串解析。我感觉用 xstrings 无法做到这一点。如果我需要切换到使用 LuaTex,那就这样吧。在学习 Lua 之前,我只是想在 LaTeX 中做到这一点

答案1

在这里,我定义了水平反射、垂直反射和顺时针旋转的宏。我首先展示了如何将它们嵌套为\myvreflect{\myrotate{\myrotate{b}}}。然后我展示了如何使用宏\mytransform来简化操作,例如vccb以递归方式完成相同的操作。

(请注意,在我的 MWE 中,“垂直”被定义为“沿垂直轴翻转”而不是“沿水平轴垂直翻转”。我这样做是为了匹配 OP 的命名法。对于“水平”,其含义也是“沿水平轴翻转”。)

已编辑以处理空参数。已重新编辑以显示如何对大于单个字符的参数进行递归操作。

\documentclass{article}
\usepackage{graphicx}
\def\myhreflect#1{\scalebox{1}[-1]{#1}}
\def\myvreflect#1{\scalebox{-1}[1]{#1}}
\def\myrotate#1{\rotatebox{90}{#1}}
\newcommand\mytransform[1]{\mytransformhelp#1\relax\relax}
\def\mytransformhelp#1#2\relax{%
  \if\relax#2\relax#1\else%
    \if v#1\myvreflect{\mytransformhelp#2\relax}\else%
      \if h#1\myhreflect{\mytransformhelp#2\relax}\else%
        \if c#1\myrotate{\mytransformhelp#2\relax}%
        \fi%
      \fi%
    \fi%
  \fi%
}
\begin{document}
b \myvreflect{\myrotate{\myrotate{b}}}

\mytransform{vccb}\quad
\mytransform{vcb}\quad
\mytransform{hccb}\quad
\mytransform{hcb}

\def\x{test}
\mytransform{vcc\x}
\end{document}

在此处输入图片描述

答案2

这是一个使用 xstring 的方法:

\documentclass{article}
\usepackage{xstring,graphicx}
\def\nestcommand#1#2{%
    \ifx#1\relax \StrSubstitute#1\relax{#2\relax}[#1]%
    \else        \StrSubstitute#1\relax{#2{\relax}}[#1]%
    \fi
}
\def\processSymbol#1{%
    \def\processcommand{\relax}%
    \edef\tempcommandset{,\unexpanded\expandafter{\commandcharlist},}%
    \def\remaining{#1}%
    \saveexpandmode\expandarg\saveexploremode\exploregroups
    \processSymbolRecurse
}
\def\processSymbolRecurse{%
    \unless\ifx\remaining\empty
        \StrSplit\remaining 1\firstchar\tempremaining
        \IfSubStr\tempcommandset{\expandafter,\firstchar=}
            {\let\remaining=\tempremaining
            \StrBehind\tempcommandset{\expandafter,\firstchar=}[\currentcommand]%
            \StrBefore\currentcommand,[\currentcommand]%
            \nestcommand\processcommand\currentcommand
            \expandafter\processSymbolRecurse
            }
            {\StrSubstitute\processcommand\relax\remaining[\processcommand]%
            \restoreexpandmode\restoreexploremode
            \expandafter\processcommand
            }%
    \fi
}
\begin{document}
\def\commandcharlist{r=\rotatebox{90},h=\scalebox{1}[-1],v=\scalebox{-1}[1],f=\fbox,b=\bfseries}%

\processSymbol{rhfy}% same as \rotate{90}{\scalebox{1}[-1]{\fbox{y}}}

\def\test{Test}
\processSymbol{fb\test} or \processSymbol{fbTest}

\def\test{b}
\processSymbol{hrr\test}
\end{document}

在此处输入图片描述

答案3

这是一个expl3版本。我不确定你想要实现什么,所以这只是一次尝试。

需要打印而不是解释的符号必须用双括号括起来。

\documentclass{article}
\usepackage{xparse}
\usepackage{graphicx}

\ExplSyntaxOn
\NewDocumentCommand\processSymbol{m}
 {
  \fallon_process_symbol:n { #1 }
 }

\tl_new:N \l__fallon_head_tl
\tl_new:N \l__fallon_tail_tl

\tl_const:Nn \c_fallon_bgroup_tl { \if_true: { \else: } \fi: }
\tl_const:Nn \c_fallon_egroup_tl { \if_false: { \else: } \fi: }

\cs_new_protected:Npn \fallon_process_symbol:n #1
 {
  \tl_clear:N \l__fallon_head_tl
  \tl_clear:N \l__fallon_tail_tl
  \tl_map_inline:nn { #1 }
   {
    \str_case:nnF { ##1 }
     {
      {v}{ \__fallon_addto_head:N \fhreflect }
      {h}{ \__fallon_addto_head:N \fvreflect }
      {c}{ \__fallon_addto_head:N \frotate }
     }
     {
      \fallon_output:n { ##1 }
     }
   }
 }

\cs_new_protected:Npn \__fallon_addto_head:N #1
 {
  \tl_put_right:Nn \l__fallon_head_tl { #1 \c_fallon_bgroup_tl }
  \tl_put_left:Nn \l__fallon_tail_tl { \c_fallon_egroup_tl }
 }

\cs_new_protected:Npn \fallon_output:n #1
 {
  \tl_put_right:Nn \l__fallon_head_tl { \exp_not:n { #1 } }
  \tl_put_right:NV \l__fallon_head_tl \l__fallon_tail_tl
  \tl_set:Nx \l__fallon_head_tl { \l__fallon_head_tl }
  \tl_use:N \l__fallon_head_tl
  \tl_clear:N \l__fallon_head_tl
  \tl_clear:N \l__fallon_tail_tl
 }

\ExplSyntaxOff

\NewDocumentCommand\fhreflect{m}{\scalebox{1}[-1]{#1}}
\NewDocumentCommand\fvreflect{m}{\scalebox{-1}[1]{#1}}
\NewDocumentCommand\frotate{m}{\rotatebox{90}{#1}}

\begin{document}

\processSymbol{vccb}\quad
\processSymbol{vcb}\quad
\processSymbol{hccb}\quad
\processSymbol{hc{{v}}}

\def\x{test}
\processSymbol{vcc\x}

\processSymbol{vccbvccy}

\end{document}

各种命令字母被转换成一个命令,该命令与隐式左括号一起附加到标记列表中,并且匹配的隐式左括号被添加到另一个标记列表中。当发现命令字母中没有的符号时,标记列表被连接起来,完全展开并传递;该过程重新开始。

在此处输入图片描述

答案4

我认为除了轮换之外你不需要任何其他包,但我可能误解了

在此处输入图片描述

但我认为你没有具体说明 rotate 应该做什么。(我\rotatebox{90}在这里假设。

\documentclass{article}
\usepackage{graphicx}
\def\zz#1{\zzz#1\zzz}

\def\zzz#1{%
\expandafter\ifx\csname\string#1!\endcsname\relax
#1%
\expandafter\zzz
\else
\csname\string#1!\expandafter\endcsname
\fi}

\expandafter\def\csname\string\zzz!\endcsname{}

\expandafter\def\csname c!\endcsname#1\zzz{%
  \rotatebox{90}{\zz{#1}}}

\expandafter\def\csname v!\endcsname#1\zzz{%
  \scalebox{1}[-1]{\zz{#1}}}

\begin{document}



\zz{vccb}

\end{document}

相关内容