¿Problema con la expansión de comandos en la macro xstring? "Incompleto \iffalse"

¿Problema con la expansión de comandos en la macro xstring? "Incompleto \iffalse"

He escrito los siguientes comandos que primero dividen el texto de entrada ;y luego crean "fracciones" a partir del texto separado por /. Mi intención con esto es mostrar genotipos con el formato adecuado.

\documentclass{article}

\usepackage{amsmath}
\usepackage{xstring}

\newcommand\genoLineDist{.2mm}
\newcommand{\genoSplit}[2]{%
    $\begin{array}{@{}c@{}}
    \text{\protect#1} \\
    \noalign{\vskip\genoLineDist}
    \hline
    \noalign{\vskip\genoLineDist}
    \text{\protect#2}
    \end{array}$%
}

\newcommand{\geno}[1]{%
    \def\remainder{#1}%
    \def\splitchar{;}%
    \genoHelper
}
\newcommand{\genoHelper}{%
    \IfSubStr{\remainder}{\splitchar}{%
        \StrBefore{\remainder}{\splitchar}[\firstpart]%
        \StrBehind{\remainder}{\splitchar}[\remainder]%
        \genoSplitHelper
        \ifx\remainder\empty
        \else
        \ ;\ \genoHelper
        \fi
    }{%
        \def\firstpart{\remainder}%
        \genoSplitHelper
    }%
}
\newcommand{\genoSplitHelper}{%
    \IfSubStr{\firstpart}{/}{%
        \StrBefore{\firstpart}{/}[\upperGeno]%
        \StrBehind{\firstpart}{/}[\lowerGenoTemp]%
        \IfSubStr{\lowerGenoTemp}{\splitchar}{%
            \StrBefore{\lowerGenoTemp}{\splitchar}[\lowerGeno]%
            \StrBehind{\lowerGenoTemp}{\splitchar}[\remainder]%
        }{\def\lowerGeno{\lowerGenoTemp}}%
        \genoSplit{\upperGeno}{\lowerGeno}%
    }{%
        \firstpart\unskip%
    }%
}

\begin{document}

%working
\geno{y w ; ap$^{DG3}$ / CyO}
%breaks
%\geno{ y w ; ap\textsuperscript{DG3} / CyO}

\end{document}

Ahora escribiendo el siguiente comando en el cuerpo del documento

\geno{y w ; ap$^{DG3}$ / CyO}

Producimos esta salida:

genotipo

Sin embargo, cuando intento incluir comandos como \textsuperscript, o símbolos como \Maleo \Femaleen cualquier lugar de la cadena de entrada, me encuentro con el siguiente error:

Incomplete \iffalse; all text was ignored after line [line with \geno command].

Mi mejor suposición es que estoy teniendo problemas con la expansión de argumentos en una de las declaraciones if, así que intenté colocar algunos \protects en lugares que sospechaba que podrían causar problemas como cuándo \remainderse define por primera vez en el \genocomando y \IfSubStrpoco éxito. También intenté usar el \MakeRobustcomando así:

%definitions above here
\MakeRobust{\geno}
\MakeRobust{\genoHelper}
\MakeRobust{\genoSplitHelper}

Pero lamentablemente el problema persistió.

Otros disparos a ciegas en la oscuridad incluyen

  • reemplazando el \ifxcon \if\relax\detokenize{\remainder}\relax(mismo error)
  • \detokenizeenviar la entrada a \IfSubStr(parece que todos devuelven un valor falso, ¿podría estar haciendo algo mal?)
  • Usar varias alternativas para el \genoSplitcomando (mismo error, ahora estoy seguro de que no es el problema)
  • Reescribiendo todos los comandos para usar \newcommandy \renewcommand(mismo error)

yo también he encontradoesta pregunta, pero no estoy seguro de que sea el mismo problema que estoy experimentando y la respuesta aceptada ( \begingroup\noexpandarg [...] \endgroup) impide que la macro funcione.

Estoy agotado y agradecería mucho saber qué está causando este problema.

Respuesta1

xstringsNo le gustan los comandos frágiles en sus argumentos.

Aquí hay una expl3implementación: primero dividimos en punto y coma; luego, cada elemento se pasa como argumento a una función que produce la fracción falsa, si /está presente.

\documentclass{article}

\usepackage{amsmath}

\newcommand\genoLineDist{.2mm}

\ExplSyntaxOn
\NewDocumentCommand{\geno}{m}
 {
  \tired_geno:n { #1 }
 }

\seq_new:N \l__tired_geno_parts_in_seq
\seq_new:N \l__tired_geno_parts_out_seq
\seq_new:N \l__tired_geno_temp_seq

\cs_new_protected:Nn \tired_geno:n
 {
  \seq_set_split:Nnn \l__tired_geno_parts_in_seq { ; } { #1 }
  \seq_set_map:NNn \l__tired_geno_parts_out_seq \l__tired_geno_parts_in_seq
   {
    \__tired_geno_split:n { ##1 }
   }
  \seq_use:Nn \l__tired_geno_parts_out_seq { \ ; \  }
 }

\cs_new_protected:Nn \__tired_geno_split:n
 {
  \seq_set_split:Nnn \l__tired_geno_temp_seq { / } { #1 }
  \int_compare:nTF { \seq_count:N \l__tired_geno_temp_seq == 1 }
   {
    #1 % no /
   }
   {
    \begin{tabular}{@{}c@{}}
    \seq_item:Nn \l__tired_geno_temp_seq { 1 } \\
    \noalign{\vskip\genoLineDist}
    \hline
    \noalign{\vskip\genoLineDist}
    \seq_item:Nn \l__tired_geno_temp_seq { 2 } \\ 
    \end{tabular}
   }
 }

\ExplSyntaxOff

\begin{document}

\geno{y w ; ap$^{DG3}$ / CyO}

\geno{ y w ; ap\textsuperscript{DG3} / CyO}

\geno{y/w ; ap$^{DG3}$ / CyO}

\end{document}

ingrese la descripción de la imagen aquí

Respuesta2

Usando solo comandos primitivos TeX puedes definir tu \genomacro de esta manera:

\def\geno#1{\def\genoS{\def\genoS{; }}\genoA #1; \end; }
\def\genoA#1; {\ifx\end#1\else
      \genoS 
      \isinslash#1/\iffalse #1\else \genoB #1/\fi
      \expandafter\genoA
   \fi
} 
\def\genoB #1/#2/{$\displaystyle{\hbox{#1\unskip}\over\hbox{\ignorespaces#2\unskip}}$ }
\def\isinslash #1/#2\iffalse{\ifx/#2/} 

\geno{y w ; ap$^{DG3}$ / CyO ; next ; A/B}

Respuesta3

Esto podría ser suficiente usando listofitemsel análisis. EDITADO para manejar la sintaxis más general especificada por el autor en el comentario.

\documentclass{article}
\usepackage{amsmath}
\usepackage{listofitems}
\newcommand\geno[1]{%
  \setsepchar[&]{;&/}%
  \readlist*\myterm{#1}%
  \foreachitem\z\in\myterm[]{%
    \ifnum\zcnt=1 \else \ ;\ \fi
    \ifnum\listlen\myterm[\zcnt]=1
      \myterm[\zcnt]%
    \else
      $\displaystyle
        \frac{\text{\myterm[\zcnt,1]}}{\text{\myterm[\zcnt,2]}}$%
    \fi
  }%
}
\begin{document}
\geno{y w ; ap$^{DG3}$ / CyO}

\bigskip
\geno{ y w ; ap\textsuperscript{DG3} / CyO}

\bigskip
\geno{ y w ; ap\textsuperscript{DG3} / CyO ;
   bp\textsuperscript{DG0} / CzO ; z x}
\end{document}

ingrese la descripción de la imagen aquí

información relacionada