Análisis recursivo de cadenas

Análisis recursivo de cadenas

He estado trabajando en escribir un procesador de flujo recursivo en látex que convierta una versión abreviada de un conjunto de comandos muy utilizados en una forma mucho más larga. El siguiente código representa lo que había hecho hasta ahora antes de darme cuenta de que xstrings no puede permitirle anidar macros.

Se supone que el programa debe hacer lo siguiente:

  • Comprueba si la entrada tiene una longitud de 0.
  • de lo contrario, verifica si hay algún comando en el primer conjunto (en este momento solo está rotar)
  • de lo contrario, comprueba si hay algún comando en el segundo conjunto (donde está flip)
  • de lo contrario simplemente devuelve el símbolo

si encuentra un símbolo, lo anida y lo llama recursivamente con los caracteres restantes en el flujo de entrada; de lo contrario, simplemente agrega la llamada recursiva al carácter actual.

Quiero mantener la naturaleza recursiva del programa porque tiene el sentido más lógico porque existe la posibilidad de que las cosas estén anidadas.

\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}
}

aunque el conjunto de comandos es arbitrario, una entrada de muestra para el código de muestra que escribí sería algo como:

vccb

que en mi código completo debería devolver algo que se verá así:

P

porque rotaría, rotaría y voltearía verticalmente la letra b.

Estoy tratando de encontrar otra forma de realizar el análisis de cadenas anidadas de esta manera. y tengo la sensación de que no se puede hacer con xstrings. Si necesito cambiar a LuaTex, que así sea. Solo intento hacer esto en LaTeX antes de necesitar aprender Lua.

Respuesta1

Aquí, defino macros para reflexión horizontal, reflexión vertical y rotación en el sentido de las agujas del reloj. Primero muestro cómo se pueden anidar como \myvreflect{\myrotate{\myrotate{b}}}. Luego muestro cómo \mytransformse puede utilizar la macro para taquigrafiar, por ejemplo, vccbpara lograr la misma cosa de forma recursiva.

(Tenga en cuenta que en mi MWE, "vertical" se define como "voltear a través de un eje vertical" y no "voltear verticalmente a través de un eje horizontal". Hago esto para poder coincidir con la nomenclatura del OP. Lo mismo ocurre con "horizontal", es decir "voltear sobre un eje horizontal".)

EDITADO para manejar argumentos nulos. REEDITADO para mostrar cómo operar de forma recursiva con argumentos de más de un solo carácter.

\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}

ingrese la descripción de la imagen aquí

Respuesta2

Aquí hay un método con 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}

ingrese la descripción de la imagen aquí

Respuesta3

Aquí tienes una expl3versión. No estoy seguro de lo que quieres lograr, así que esto es sólo un intento.

Un símbolo que deba imprimirse en lugar de interpretarse debe encerrarse entre llaves dobles.

\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}

Las distintas letras de comando se transforman en un comando que se agrega a una lista de tokens junto con una llave de apertura implícita y se agrega una llave de apertura implícita coincidente en otra lista de tokens. Cuando se encuentra un símbolo que no está entre las letras de comando, las listas de tokens se unen, se expanden completamente y se entregan; el proceso se inicia de nuevo.

ingrese la descripción de la imagen aquí

Respuesta4

No creo que necesites ningún paquete más que para la rotación, pero es posible que haya entendido mal cuando entiendo

ingrese la descripción de la imagen aquí

Pero no creo que hayas especificado qué se suponía que debía hacer exactamente la rotación. (Asumí \rotatebox{90}aquí.

\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}

información relacionada