![Análise recursiva de strings](https://rvso.com/image/305748/An%C3%A1lise%20recursiva%20de%20strings.png)
Tenho trabalhado na escrita de um processador de fluxo recursivo em látex que converte uma versão abreviada de um conjunto de comandos altamente usados em um formato muito mais longo. O código abaixo representa o que eu fiz até agora antes de perceber que xstrings não pode permitir aninhar macros.
O programa deve fazer o seguinte:
- Verifica se a entrada tem comprimento 0.
- caso contrário, ele verifica se há algum comando no primeiro conjunto (agora é apenas girar)
- caso contrário, ele verifica se há algum comando no segundo conjunto (onde está o flip)
- caso contrário, apenas retorna o símbolo
se encontrar um símbolo, ele aninha e chama recursivamente com os caracteres restantes no fluxo de entrada; caso contrário, apenas anexa a chamada recursiva ao caractere atual.
Quero manter a natureza recursiva do programa porque isso faz mais sentido lógico porque existe a possibilidade de as coisas serem aninhadas
\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}
}
embora o conjunto de comandos seja arbitrário, um exemplo de entrada para o código de exemplo que escrevi seria algo como:
vccb
que deve retornar em meu código completo algo parecido com:
P
porque iria girar, girar e virar verticalmente a letra b.
Estou tentando descobrir outra maneira de analisar strings aninhadas dessa maneira. e tenho a sensação de que isso não pode ser feito com xstrings. Se eu precisar mudar para o LuaTex, que assim seja. estou apenas tentando fazer isso em LaTeX antes de precisar aprender Lua
Responder1
Aqui, defino macros para reflexão horizontal, reflexão vertical e rotação no sentido horário. Primeiro mostro como eles podem ser aninhados como arquivos \myvreflect{\myrotate{\myrotate{b}}}
. Em seguida, mostro como a macro \mytransform
pode ser usada para taquigrafar, como vccb
para realizar recursivamente a mesma coisa.
(Observe em meu MWE, "vertical" é definido como "virar verticalmente em um eixo vertical" e não "virar verticalmente em um eixo horizontal". Eu faço isso para poder corresponder à nomenclatura do OP. Da mesma forma para "horizontal", significando "virar em um eixo horizontal".)
EDITADO para lidar com argumentos nulos. REEDITADO para mostrar como operar recursivamente em argumentos maiores que um único caractere.
\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}
Responder2
Aqui está um método com 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}
Responder3
Aqui está uma expl3
versão. Não tenho certeza do que você deseja alcançar, então esta é apenas uma tentativa.
Um símbolo que deva ser impresso em vez de interpretado deve ser colocado entre colchetes duplos.
\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}
As várias letras de comando são transformadas em um comando que é anexado a uma lista de tokens junto com uma chave de abertura implícita e uma chave de abertura implícita correspondente é adicionada em outra lista de tokens. Quando um símbolo que não está entre as letras de comando é encontrado, as listas de tokens são unidas, totalmente expandidas e entregues; o processo é reiniciado.
Responder4
Eu não acho que você precise de nenhum pacote além da rotação, mas posso ter entendido mal quando entendi
Mas não acho que você especificou o que a rotação deveria fazer exatamente. (presumi \rotatebox{90}
aqui.
\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}