![Rekursives String-Parsing](https://rvso.com/image/305748/Rekursives%20String-Parsing.png)
Ich habe daran gearbeitet, einen rekursiven Stream-Prozessor in Latex zu schreiben, der eine Kurzform einer Reihe häufig verwendeter Befehle in eine viel längere Form umwandelt. Der folgende Code stellt dar, was ich bisher getan habe, bevor mir klar wurde, dass xstrings das Verschachteln von Makros nicht zulassen.
Das Programm soll folgendes leisten:
- Überprüft, ob die Eingabe die Länge 0 hat.
- andernfalls wird geprüft, ob im ersten Satz Befehle vorhanden sind (im Moment gibt es nur „Rotate“)
- andernfalls wird geprüft, ob im zweiten Satz (wo flip ist) Befehle vorhanden sind.
- andernfalls wird nur das Symbol zurückgegeben
Wenn es ein Symbol findet, verschachtelt es es und ruft es rekursiv mit den verbleibenden Zeichen im Eingabestrom auf, andernfalls hängt es den rekursiven Aufruf einfach an das aktuelle Zeichen an.
Ich möchte die rekursive Natur des Programms beibehalten, da dies am logischsten ist, da die Möglichkeit besteht, dass Dinge verschachtelt werden
\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}
}
Obwohl der Befehlssatz beliebig ist, würde eine Beispieleingabe für den Beispielcode, den ich geschrieben habe, etwa so aussehen:
vccb
Das sollte in meinem vollständigen Code etwa so aussehen:
P
weil es den Buchstaben b drehen, rotieren und vertikal spiegeln würde.
Ich versuche, eine andere Möglichkeit zu finden, verschachtelte Strings auf diese Weise zu analysieren. Und ich habe das Gefühl, dass das mit xstrings nicht geht. Wenn ich auf LuaTex umsteigen muss, dann ist das so. Ich versuche das gerade in LaTeX zu machen, bevor ich Lua lernen muss.
Antwort1
Hier definiere ich Makros für horizontale und vertikale Spiegelung sowie Drehung im Uhrzeigersinn. Zuerst zeige ich, wie sie verschachtelt werden können \myvreflect{\myrotate{\myrotate{b}}}
. Dann zeige ich, wie Makros \mytransform
verwendet werden können, um Abkürzungen zu verwenden, beispielsweise vccb
um rekursiv dasselbe zu erreichen.
(Beachten Sie, dass in meinem MWE „vertikal“ als „um eine vertikale Achse kippen“ und nicht als „vertikal um eine horizontale Achse kippen“ definiert ist. Ich mache das so, damit ich der Nomenklatur des OP entsprechen kann. Gleiches gilt für „horizontal“, was „um eine horizontale Achse kippen“ bedeutet.)
BEARBEITET, um Nullargumente zu verarbeiten. NEU BEARBEITET, um zu zeigen, wie rekursiv mit Argumenten verfahren wird, die größer als ein einzelnes Zeichen sind.
\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}
Antwort2
Hier ist eine Methode mit 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}
Antwort3
Hier ist eine expl3
Version. Ich bin nicht sicher, was Sie erreichen möchten, daher ist dies nur ein Versuch.
Ein Symbol, das gedruckt und nicht interpretiert werden soll, muss in doppelte Klammern eingeschlossen werden.
\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}
Die verschiedenen Befehlsbuchstaben werden in einen Befehl umgewandelt, der zusammen mit einer impliziten öffnenden Klammer an eine Tokenliste angehängt wird, und eine passende implizite öffnende Klammer wird in einer anderen Tokenliste hinzugefügt. Wenn ein Symbol gefunden wird, das nicht unter den Befehlsbuchstaben ist, werden die Tokenlisten zusammengeführt, vollständig erweitert und übermittelt; der Vorgang wird von vorne begonnen.
Antwort4
Ich glaube nicht, dass Sie andere Pakete als für die Rotation benötigen, aber ich habe es vielleicht falsch verstanden, da ich
Aber ich glaube nicht, dass Sie genau angegeben haben, was „Rotate“ bewirken sollte. (Das habe ich \rotatebox{90}
hier angenommen.
\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}