Análise recursiva de strings

Análise recursiva de strings

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 \mytransformpode ser usada para taquigrafar, como vccbpara 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}

insira a descrição da imagem aqui

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}

insira a descrição da imagem aqui

Responder3

Aqui está uma expl3versã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.

insira a descrição da imagem aqui

Responder4

Eu não acho que você precise de nenhum pacote além da rotação, mas posso ter entendido mal quando entendi

insira a descrição da imagem aqui

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}

informação relacionada