재귀적 문자열 분석

재귀적 문자열 분석

나는 자주 사용되는 명령 세트의 단축 버전을 훨씬 더 긴 형식으로 변환하는 재귀적 스트림 프로세서를 라텍스로 작성하는 작업을 해왔습니다. 아래 코드는 xstring을 사용하여 매크로를 중첩할 수 없다는 사실을 깨닫기 전에 지금까지 수행한 작업을 나타냅니다.

이 프로그램은 다음을 수행하도록 되어 있습니다.

  • 입력 길이가 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의 명명법과 일치시킬 수 있도록 이렇게 합니다. "수평"도 마찬가지입니다. "가로축을 가로질러 뒤집기".)

null 인수를 처리하도록 편집되었습니다. 단일 문자보다 큰 인수에 대해 재귀적으로 작동하는 방법을 보여주기 위해 다시 편집되었습니다.

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

관련 정보