I am writing a macro that will read a system of linear equations in a custom format and call \begin{array} with the appropriate format. For that I need to loop through each row and compute what is going to be displayed.

This is what I have so far.

\documentclass[10pt,a4paper]{article}
\usepackage{xstring}

\newcommand{\lineareqsys}[3]{
\noexpandarg
\StrCount{#3}{\\}[\rows] %check \rows = arg > 0
\newcounter{i} \setcounter{i}{0}
\def\str{#3}
\def\strout{}
\expandafter\StrSubstitute\expandafter{\str}{+}{+&}[\str]
\expandafter\StrSubstitute\expandafter{\str}{-}{-&}[\str]
\loop
\stepcounter{i}
\expandafter\def\csname strout\roman{i}\endcsname{}
\expandafter\StrCut\expandafter{\str}{\\}{\str}{\rest}
\expandafter\StrPosition\expandafter{\str}{x}[\xpos]
\expandafter\StrLeft\expandafter{\str}{\xpos}[\strappx]
\expandafter\def\expandafter\strout\expandafter{\strout \strappx &}
\expandafter\StrGobbleLeft\expandafter{\str}{\xpos}[\str]
\expandafter\StrPosition\expandafter{\str}{y}[\ypos]
\expandafter\StrLeft\expandafter{\str}{\ypos}[\strappy]
\expandafter\def\expandafter\strout\expandafter{\strout \strappy &}
\expandafter\StrGobbleLeft\expandafter{\str}{\ypos}[\str]
\expandafter\StrPosition\expandafter{\str}{=}[\eqpos]
\expandafter\StrLeft\expandafter{\str}{\eqpos}[\strappeq]
\expandafter\def\expandafter\strout\expandafter{\strout \strappeq &}
\expandafter\StrGobbleLeft\expandafter{\str}{\eqpos}[\str]
\expandafter\StrRight\expandafter{\str}{\eqpos}[\strapplb]
\expandafter\def\expandafter\strout\expandafter{\strout \strapplb \\}
\expandafter\def\expandafter\str\expandafter{\rest}
\expandafter\def\csname strout\roman{i}\endcsname{\strout}
\ifnum \thei < #1 \relax
\repeat
\newcounter{j} \setcounter{j}{0}
\def\alig{r}
\loop
\stepcounter{j}
\expandafter\def\expandafter\alig\expandafter{\alig cr}
\ifnum \thej < #2 \relax
\repeat
\left\lbrace
\begin{array}{\alig}
\strout
\end{array}
\right.
}


\begin{document}
$\lineareqsys{2}{2}{
x + y = 5 \\
x - y = 3 \\
}$
\end{document}

There is a problem with line

\expandafter\def\csname strout\roman{i}\endcsname{\strout}

because \strout is not fully expanded, so after the second time of the loop data is replaced and I get the last row repeated twice.

I've been checking other threads but I haven't managed to get it right. How can I solve this problem?

Note1: The code isn't finished so it doesn't handle the cases where there is no x or y or a line starts with a - sign.

Note2: The format I was referring to is straightforward.

ax + by + cz = d \\

for as many rows as necessary.

Edit: Simpler version of previous code.

\documentclass{article}
\newcommand{\lineareqsys}{
\newcounter{i} \setcounter{i}{0}
\def\strout{}
\loop
\stepcounter{i}
\expandafter\def\expandafter\strout\expandafter{\strout \arabic{i} row \\}
\ifnum \thei < 2 \relax
\repeat
\begin{array}{l}
\strout
\end{array}
}
\begin{document}
$\lineareqsys$
\end{document}

This ilustrates the same problem. \arabic{i} is expanded at the end when it's value is 2. Not dinamic.

  • 2
    if you know that \strout is safe for expansion then just replace \def by \edef or if you just want to expand it once then expandafter\def\csname strout\roman{i}\expandafter\endcsname\expandafter{\strout} but the code seems massively over complicated, can you give a small text description of the intended effect? – David Carlisle Nov 14 '17 at 9:38
  • \edef gives a compile time error. I think because it relays on #3 but I'm not sure if this is the reason. – mendus Nov 14 '17 at 9:43
  • Do you know about the systeme package? – egreg Nov 14 '17 at 9:46
  • don't do \newcounter inside a command! (you do it twice) – jfbu Nov 14 '17 at 9:48
  • @egreg Yes, I had found it previously. I wanted to write my own functions though, so I can add things as I see fit. – mendus Nov 14 '17 at 10:01
up vote 2 down vote accepted

The core problem is that you are not expanding things. As you can see, here is meaning of \strout after a while

> \strout=macro:
->\strappx &\strappy &\strappeq &\strapplb \\\strappx &\strappy &\strappeq &\st
rapplb \\.
\iterate ... {\strout \strapplb \\} \show \strout 
                                                  \expandafter \def \expanda...
l.57 }
      $

You have to find a way to add to \strout the expanded contents of the \strappx, \strappy etc... whatever they are.

Besides, you do \newcounter inside your command call, which is very wrong. But this is other issue.

To debug, I added \show\strout at various places of your command.

Also you are lucky to call this macro only in math mode because you have tons of space tokens in it.


For example, this can give an idea of what needs to be done:

%\expandafter\def\expandafter\strout\expandafter{\strout \strapplb \\}
\expandafter\g@addto@macro\expandafter\strout\expandafter{\strapplb\\}

enter image description here

The RHS of first equation is fixed.

  • This works. Any alternative to \g@addto@macro by any chance? – mendus Nov 14 '17 at 10:19
  • well, \edef\strout{\unexpanded\expandafter{\strout}\unexpanded\expandafter{\strapplb\\}} should work (pay attention that copying pasting from this comment might introduce some invisible Unicode, due to the site interfering; better copy by hand). Beware that \g@addto@macro is global, so if you use it make global all other manipulations of \strout to follow good practices. – jfbu Nov 14 '17 at 11:49
  • this being said, it would not be too complicated to replace by delimited macros all your invocations of xstring ... and the various pieces would then be available "raw" not incorporated in a macro. – jfbu Nov 14 '17 at 11:51
  • I don't understand what you mean with the last comment. How do I search for x, y and z and how do I cut the users input into two pieces without a string package? Can you refer me to some documentation? I'm pretty new to TeX, previously I've only used high level LaTeX commands. – mendus Nov 15 '17 at 7:42
  • maybe my comment was a bit rushed. TeX has a a powerful concept of delimited macros, on which evidently packages such as xstring build up, or xparse. If you happen to know about TeX, it is natural to feel you don't really need xstring, but it also means you have your own coding habits and possibly you re-invent the wheel each time. If x, y, z are always in that order, delimited macros will solve easily problem. If the order maybe z, y, x, then they will too (only available tool after all) but require more expertise. TeX by Topic (texdoc topic) is recommended. – jfbu Nov 15 '17 at 8:16

There are big expansion problems, as you saw.

Here's a completely different solution, which uses expl3, but has, like yours, the defect that missing unknowns spoil the result.

I also offer a comparison with systeme, that doesn't suffer from the defect.

\documentclass[10pt,a4paper]{article}
\usepackage{xparse}
%\usepackage{array} % also works with this uncommented
\usepackage{systeme} % for comparison

\ExplSyntaxOn
\NewDocumentCommand{\lineareqsys}{mm}
 {
  \seq_set_split:Nnn \l__mendus_system_in_seq { \\ } { #2 }
  \seq_clear:N \l__mendus_system_out_seq
  \seq_map_inline:Nn \l__mendus_system_in_seq
   {
    \__mendus_system_make_row:nn { #1 } { ##1 }
   }
  \left\lbrace
  \setlength{\arraycolsep}{0pt}
  \renewcommand{\arraystretch}{1.2}
  \exp_args:Nnx \begin{array}{r \prg_replicate:nn { \clist_count:n { #1 } } { c r } }
  \seq_use:Nn \l__mendus_system_out_seq { \\ }
  \end{array}
  \right.
 }

\cs_new_protected:Nn \__mendus_system_make_row:nn
 {
  \tl_set:Nn \l__mendus_system_row_tl { #2 }
  \regex_replace_all:nnN { (.+?)(\+|\-|\=) } { \1\cB\{\cE\}\2\cB\{\cE\}\cT& } \l__mendus_system_row_tl
  \clist_map_inline:nn { #1 }
   {
    \regex_replace_all:nnN { ##1 } { \cL##1 \cT& } \l__mendus_system_row_tl
   }
  \seq_put_right:NV \l__mendus_system_out_seq \l__mendus_system_row_tl
 }
\cs_generate_variant:Nn \regex_count:nnN { nV }
\ExplSyntaxOff

\begin{document}

\[
\lineareqsys{x,y}{
x + y = 5 \\
x - y = 3 \\
}
\qquad
\lineareqsys{x,y,z}{
  2x-3y+4z=0 \\
  x+12y-z=0 \\
  -x+8y+z=3
}
\]

\[
\systeme{
  x + y = 5,
  x - y = 3
}
\qquad
\systeme{
  2x-3y+4z=0,
  x+12y-z=0,
  -x+8y+z=3
}
\]

\end{document}

enter image description here

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.