![遞歸字串解析](https://rvso.com/image/305748/%E9%81%9E%E6%AD%B8%E5%AD%97%E4%B8%B2%E8%A7%A3%E6%9E%90.png)
我一直致力於用 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
我認為除了輪換之外你不需要任何軟體包,但我可能誤解了
但我認為您沒有具體說明旋轉應該做什麼。 (我假設\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}