1

I have written the following commands which first chunk the input text by ; and then make "fractions" out of text that is separated by /. My intention with this is to display genotypes with propper formatting.

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

Now by typing the following command in the document body

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

We produce this output:

genotype

However, when I try to include any commands like \textsuperscript, or symbols like \Male or \Female anywhere in the input string, I run into the following error:

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

My best guess is that I'm running into issues with argument expansion in one of the if statements, so I tried placing some \protects in places I suspected could cause issues like when \remainder is first defined in the \geno command and the \IfSubStr to little success. I have also attempted to use the \MakeRobust command like so:

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

But unfortunately the problem persisted.

Other blind shots in the dark include

  • replacing the \ifx with \if\relax\detokenize{\remainder}\relax (same error)
  • \detokenizeing the input to \IfSubStr (seems like they all return a false, might be doing something wrong?)
  • Using various alternatives for the \genoSplit command (same error, I am now positive it is not the issue)
  • Rewriting all commands to use \newcommand and \renewcommand (same error)

I have also found this question, but I am not sure this is the same issue I'm experiencing, and the accepted answer (\begingroup\noexpandarg [...] \endgroup) prevents the macro from working.

I'm at my wit's end and would greatly appreciate some insight into what is causing this issue.

2
  • 1
    always provide a small but complete example. That makes it much easier to test your issue. Commented Jan 14, 2024 at 17:57
  • @UlrikeFischer Sorry about that, I've updated the first codeblock to work as a complete example now. Commented Jan 14, 2024 at 18:22

3 Answers 3

0

xstrings doesn't like fragile commands in its arguments.

Here's an expl3 implementation: first we split at semicolons; then each item is passed as argument to a function that produces the fake fraction, if / is present.

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

enter image description here

1
  • Thank you very much, this is perfect! expl3 seems really useful. Is there a resource you'd recommend to learn more about it, or should I just jump into the documentation? Commented Jan 14, 2024 at 20:40
3

Using only TeX primitive commands you can define your \geno macro like this:

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

This might suffice, using listofitems parsing. EDITED to handle the more general syntax specified by the author in the comment.

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

enter image description here

2
  • Thank you very much. Unfortunately it needs to display up to four different "list entries" that each should have the option to be a fraction, e.g. oneA / oneB ; two ; threeA / threeB ; fourA / fourB etc. Commented Jan 14, 2024 at 19:31
  • @tired63194 I have EDITED my answer to handle the more general situation you specify in your comment. Commented Jan 15, 2024 at 0:05

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.