0

This is another chapter of the story "how to use a moodle database for my purposes". The accepted answer to this question gives a very effective way to retrieve informations from an exercise database structured as follows

\begin{multi}{}
  Text
  \item first answer
  \item* correct anser
  ...
 \end{multi}

Now, the object retrieved as "nth answer" contains all kind of spacing, for instance

  \item

first answer

will store the \par.

I would like to erase all kind of "blank" spaces before the start of the actual aswer, for editing purpose.


An example for the Wipet answer which does not fit in a comment. If I set

  \documentclass{article}
  \usepackage{getitems}
  \begin{document}

\def\item{\futurelet\next \itemA} \def\itemA{\ifx\next\par \expandafter\itemB \fi} \long\def\itemB#1{\item}

\def\A{

A}

\def\B{%

B}

X\expandafter\item\A X

X\expandafter\item\B X \end{document}

The output is

 X
 AX
 XBX

So \expandafter\item\A does not work (it includes a linebreak before A) while \expandafter\item\B works (it does not include a linebreak before B)

Ulrich Diez
  • 28,770
  • \tl_head, \tl_tail and \tl_if_eq etc. should be sufficient – user202729 May 15 '22 at 08:57
  • @user202729 what is the usage of such? – user126154 May 16 '22 at 08:38
  • by the way: I need also to remove empty lines AFTER my object – user126154 May 16 '22 at 11:05
  • @user202729 I tried something like \NewDocumentCommand{\HEAD}{ m }{\tl_head:N { #1 }} and \NewDocumentCommand{\TAIL}{ m }{\tl_tail:N { #1 }} and then \HEAD\A\TAIL\A, with \A as in the question, and does not work (whil it works with \B) – user126154 May 16 '22 at 21:39
  • Sorry, it is not full example. In what context is used \def\A{...}\def\B{...}, i.e. what is around them? How the \item is defined? Full example means that it can be used without adding another context which I don't know. Full example is full document. – wipet May 17 '22 at 04:33
  • @wipet my real life full example is the second code of the accepted answer to this question https://tex.stackexchange.com/questions/644183/how-to-check-that-something-starts-with-or-how-to-build-your-own-exercise-she/644222#644222 where its is constructed a macro which handle a moodle database extracting all items of an exercise: text, answers, correct answers, and store them in some macro. Then I use those defined macros for building my exercise sheets. But those macros contains everything it is between two \item, included blank lines, and this fact bugs my final rendering, – user126154 May 17 '22 at 06:39
  • @wipet see also this question https://tex.stackexchange.com/questions/644469/problem-with-spaces-and-getitems-package/644472#644472 in which I tryed to isolate the issue in a simple code – user126154 May 17 '22 at 06:41
  • Your examples mentioned in your last comments don't include \def\A nor \def\B. So, I still don't know, how looks like your full example with \def\A and \def\B and \expandafter\item\A and \expandafter\item\B. You are talking that it does not work and I am unable to construct a full example which documents your claim. I am waiting for full example or we close this discussion. – wipet May 17 '22 at 10:43
  • @wipet added a full code of "non working" example – user126154 May 17 '22 at 12:38
  • You have \def\A{ but should be \def\A{%. The \item macro skips only \par tokens, no spaces. My firs idea were that \item is followed by the real text, so there is no spaces immediately after \item. But the space were propagated from expanded macro \A in your example. – wipet May 17 '22 at 14:20
  • Why aren't you using the code I suggested? It just requires to have an up-to-date release of the TeX system. – egreg May 17 '22 at 21:41
  • @greg The first reason is very silly: I have some problem with the repositories of ubuntu which I need to solve, and it takes some times. I'm usign overleaf for tests in this period but it seems that also overleaf is not completely up to date. The second reason is that I work with existing moodle databases, and, if I have understud correclty, your code does not accept itemize inside questions and aswers (but I cannot test it untill I get my upgrade). – user126154 May 18 '22 at 09:31

2 Answers2

3

The \item control sequence consumes all space after it at during tokenization. So, you want to remove only blank lines tokenized as \par. If you don't asking for expandable macro, the solution can look like this:

\def\item{\futurelet\next \itemA}
\def\itemA{\ifx\next\par \expandafter\itemB \fi}
\long\def\itemB#1{\item}

test:

aaa% \item

bbb

\bye

Another approach: Suppose we have defined something like this:

\def\TEXT{
\item

a b c \item d e f

g h i }

and we want to create a new macro \TEXT where all \par immediately followed by \item are removed. It means that the two \pars after first \item are removed in our example but the \par between d e f and g h i is kept. We can do this by

\rempars\TEXT

This macro changes the body of the \TEXT as mentioned above. This macro can be defined by:

\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\long\def\afterfi#1#2\fi{\fi#1}
\def\rempars #1{%
   \let\orig=#1%
   \def\tmp{}%
   \expandafter\remparsA #1\item\par\endrempars
   \expandafter\def\expandafter#1\expandafter{\tmp}%
   \ifx#1\orig\else \afterfi{\rempars#1}\fi
}
\long\def\remparsA #1\item\par#2\endrempars{%
   \if\relax\detokenize{#2}\relax \addto\tmp{#1}%
   \else \addto\tmp{#1\item}\afterfi{\remparsA #2\endrempars}\fi
}
wipet
  • 74,238
  • maybe I was not so clear. Everything is part of macros that I use for producing some Exams shet from moodle database, as in here https://tex.stackexchange.com/questions/644183/how-to-check-that-something-starts-with-or-how-to-build-your-own-exercise-she/644222#644222 . So getitems already parses \item occurrences, than therefore disappear. All text between \items is stored in a macro \gathereditem{n} and I would like to extract the information as \def\mymacro{content of \gathereditem with spaces removed} – user126154 May 15 '22 at 10:06
  • Before the text is gathered (it is separated by what?) then you can set the TeX register \endlinechar to -1. It suppresses the conversion of blank lines to \par. I don't know the whole context, so I cannot say more. – wipet May 15 '22 at 10:34
  • before the text is gathered it is in the form \begin{multi}{} text of exercise \item first answer \item another answer \item* correct answer ... \end{multi} and getitems.sty package parses it. – user126154 May 15 '22 at 12:28
  • could you explain what exactly does your code? it seems looping – user126154 May 16 '22 at 11:33
  • also I tried to turn your code in a macro but it does not work. basically because \def\TEST{\par \par \par test} and then \item\TEST don'e see the \par (because the braces are there?) – user126154 May 16 '22 at 15:04
  • \expandafter\item\TEST – wipet May 16 '22 at 16:18
  • That's strange. \expandafer works if I have \def\TEST{\par \par test} but doesn't if, instead of \par I have blank lines (like as in the example of the original question) – user126154 May 16 '22 at 19:30
  • It needs full example what you are doing. Such example cannot be included in the comment. – wipet May 16 '22 at 20:21
  • added example in the question – user126154 May 16 '22 at 21:09
  • @user126154 I added another approach which can solve your problem. I suppose that you have accumulated the text in a macro \TEXT and you want to do corrections in it. – wipet May 17 '22 at 18:41
  • the new macro does not fit with my need. My accumulated text is not stored as in your example, it is stored by themacro \gatheritems. I guess that in my case \TEXT is something like \par \par some text that may contains nested enviromnent like itemize \par \par \par and I want to remove all initial and final \par. Se here for an example of situation that I need to handle https://tex.stackexchange.com/questions/644469/problem-with-spaces-and-getitems-package/644472#644472 – user126154 May 18 '22 at 12:35
1

Add something to the code I suggested last time.

\documentclass{article}
\usepackage{amsthm}
\usepackage{enumitem}

\newcounter{exercise}

\ExplSyntaxOn

\NewDocumentEnvironment{multi}{m +b} { \par\addvspace{\topsep}\setlength{\parindent}{0pt} \stepcounter{exercise} \textbf{Exercise~\theexercise}~--~#1\par\nobreak \moodle_multi:n { #2 } \par\addvspace{\topsep} } {}

\NewDocumentCommand{\showcorrect}{} { \bool_gset_true:N \g_moodle_multi_correct_bool } \NewDocumentCommand{\hidecorrect}{} { \bool_gset_falsee:N \g_moodle_multi_correct_bool }

\bool_new:N \g_moodle_multi_correct_bool \seq_new:N \l__moodle_multi_text_seq \tl_new:N \l__moodle_multi_text_tl \tl_new:N \l__moodle_multi_moretext_tl \tl_new:N \l__moodle_multi_answers_tl

\cs_new_protected:Nn \moodle_multi:n { \regex_split:nnN { {(enumerate|itemize)} } { #1 } \l__moodle_multi_text_seq \tl_set:Nx \l__moodle_multi_answers_tl { \seq_item:Nn \l__moodle_multi_text_seq { -1 } } \tl_set:Nn \l__moodle_multi_text_tl { #1 } \regex_replace_once:nnN { (.)\u{l__moodle_multi_answers_tl} } { \1 } \l__moodle_multi_text_tl \seq_set_split:NnV \l__moodle_multi_text_seq { \item } \l__moodle_multi_answers_tl % the first item will contain the question text \seq_pop_left:NN \l__moodle_multi_text_seq \l__moodle_multi_moretext_tl \tl_use:N \l__moodle_multi_text_tl \tl_use:N \l__moodle_multi_moretext_tl % now we rebuild the answers \begin{enumerate}[label=(\Alph),nosep,labelsep=0.75em] \use:e {% add the first \item and put it also between the other items __moodle_multi_item: \seq_use:Nn \l__moodle_multi_text_seq { __moodle_multi_item: } } \end{enumerate} }

\cs_new_protected:Nn __moodle_multi_item: { \item \peek_charcode_remove:NT * {% there is an asterisk \bool_if:NT \g_moodle_multi_correct_bool { __moodle_multi_correct: } __moodle_multi_ignore: } }

\cs_new_protected:Nn __moodle_multi_correct: { \makebox[0pt][r]{\makebox[0pt][l]{$^{\scriptscriptstyle*}$}\hspace{\labelsep}} }

\cs_new_protected:Nn __moodle_multi_ignore: {% remove blank spaces and \par \peek_regex_remove_once:nTF { [\s\c{par}]* } {} {} }

\ExplSyntaxOff

\begin{document}

\begin{multi}{Name of the question} Text of the question \begin{itemize} \item a \item b \end{itemize} More text \begin{enumerate} \item a \item b \end{enumerate} More text \item first answer \item

second answer \item* the starred is the correct answer \end{multi}

\showcorrect

\begin{multi}{Name of the question} Text of the question \item first answer \item second answer \item*

the starred is the correct answer \end{multi}

\end{document}

enter image description here

egreg
  • 1,121,712
  • my LaTeX is not up to date: I have no\peek_regex_remove_once – user126154 May 16 '22 at 15:06
  • @user126154 Update. – egreg May 16 '22 at 15:26
  • by the way: your code is much cleaner than all other solutions I found/build without expl3. It's clear that expl3 is the right solution for "programming" with latex. – user126154 May 18 '22 at 09:39
  • @greg I don't know exacly how your code works, but it seems that it searches for all instances of \item, and this is probably the problem with itemize environment inside questions/answers. This seems the same way listofitems package do (and in fact it has the same problem). On the other hand getitems has not this problem. I don't know if one could take inspiration from that and use the same receipt with expl3. Probably yes, but I don't know. – user126154 May 18 '22 at 09:39
  • @user126154 Not with the latest version. – egreg May 18 '22 at 09:44
  • so the latest version of your code accepts itemize? – user126154 May 18 '22 at 09:46
  • @user126154 I'm referring to https://tex.stackexchange.com/a/644322/4427 where you can see both enumerate and itemize in the “text” part. Anyway, trying to coerce bad markup is a waste of time. It takes less to edit the texts to use something else than \item in the “answers” part. – egreg May 18 '22 at 09:55
  • I see. Well the fact is that first, I need to use existing moodle database (which are written with \item) and second, the script should be available to all my collegues, so it has to be something that "works out of the box" with any moodle database that they have. – user126154 May 18 '22 at 09:57
  • You are right, searching for "bad markup" is a waste of time. However, it seems to me that \getitmes does not do that: it just seems to recognize the beginning of enviroments inside text and aswer and take them without parsing inside them. May be one could do in a similar way with come expl3 command – user126154 May 18 '22 at 10:01
  • In the doc package of getitems there is the whole code commented, and this issues is explicitly discussed. It seems that it takes few lines to solve it, but my knowledge is not enough to pick what I need from that code. – user126154 May 18 '22 at 12:44
  • @user126154 I provided you fully functioning code fulfilling the requests, which does work out of the box on any up-to-date TeX system. If you don't want to use it, that's your choice. – egreg May 18 '22 at 13:30
  • Oh, I will test and use it. That's sure :) My concerns is: ok we checked for occurrences of itemize and enumerate but it may happens that answers contain some other nested environment invoking some \item command, and in this case the code would probably stop working. So, a solution in style of getitems would be more appropiate. – user126154 May 18 '22 at 13:51