1

I tried to create a command that concatenates multiple strings together. The first source defines a new command \merge that takes two parameters and prints them without any spaces between them. The \noindent at the beginning prevents indents at the beginning of a paragraph. It worked without issues.

\documentclass{article}
\begin{document}

\newcommand\merge[2] {%
    \noindent#1#2
}%

\merge{12}{34} \\
\merge{hello}{ nice to meet you} \\
\merge{latex }{is so hard}
\end{document}

Output:

1234
hello nice to meet you
latex is so hard

Then I defined a string to be used as the command via \xdef. It does the exact same thing as the first one and also works fine.

\documentclass{article}
\begin{document}

\newcommand\merge[2] {%
    \xdef\tempstring {%
        \noindent#1#2
    }%
    \tempstring
}%

\merge{12}{34} \\
\merge{hello}{ nice to meet you} \\
\merge{latex }{is so hard}
\end{document}

Output:

1234
hello nice to meet you
latex is so hard

Finally I tried creating a command \nmergeinit that takes an integer as its sole parameter, which is used to define another command \nmerge that is supposed to concatenate n strings. This time I use a \foreach loop to create the string #1#2#3...#n. Then it is placed within \nmerge to be executed. To use this command, \nmergeinit should always be called first so that \nmerge can take the correct amount of strings. The code did compile without issues, but instead of #k being replaced with the parameters, the output was always #1#2#3...#n itself.

My guess is that \# guarantees that a literal sharp is passed with no chance of being interpreted as a parameter sign later on. However if I were to remove the escaping backslash the code would not compile as the compiler tries to interpret the sharp immediately. So I need to find solution where the sharp is not interpreted when the command is made, but is interpreted when it is executed. What can I do to make \nmerge behave as expected?

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

\newcommand\nmergeinit[1] {%
    \xdef\tempcommand {%
    }%
    \foreach \i in {1,...,#1} {%
        \xdef\tempcommand {%
            \tempcommand\#\i
        }%
    }%
    \providecommand\nmerge {%
    }%
    \renewcommand\nmerge[#1] {%
        \noindent\tempcommand
    }%
}%

\nmergeinit{6}
\nmerge{12}{34}{56}{78}{90}{12} \\
\nmergeinit{5}
\nmerge{hello }{nice }{to }{meet }{you} \\
\nmergeinit{4}
\nmerge{latex }{is }{so }{hard}
\end{document}

Expected Output:

123456789012
hello nice to meet you
latex is so hard

Actual Output:

#1#2#3#4#5#6
#1#2#3#4#5
#1#2#3#4
3

4 Answers 4

2

I understand that you want to declare a macro with variable numbers of parameters in a loop. Another concept is to create a macro with single parameter which is executed in a loop, but this is not your task.

You can to do this by \h which is set to \relax when \params is build in the loop and it is set to ## when \params is used. For example, after \nmergeinit3 we have \h1\h2\h3 in \params and then it is expanded to ##1##2##3. The \def\h{####} is used in fact because then \h includes real ## (it is defined inside \nmergeinit) and we want to use double # because \nmerge is defined inside \nmergeinit too.

\newcount\tmpnum
\def\nmergeinit#1{%
   \let\h=\relax \def\params{}
   \tmpnum=0
   \loop
      \ifnum\tmpnum<#1 
         \advance\tmpnum by1
         \edef\params{\params\h\the\tmpnum}
      \repeat
   \def\h{####}
   \expandafter\def\expandafter\nmerge\expanded{\params{\params}}
}

\nmergeinit3
\meaning\nmerge
2

Within your attempt one can find

\renewcommand\nmerge[#1] {%
    \noindent\tempcommand
}%

This does not work out: You need to distinguish the moment in time when a macro is defined from the moment in time when a macro is carried out=expanded for obtaining its replacement text:

At the moment of defining the macro \nmerge TeX does not see the sequences hashes (#) and digits that make the definition/replacement text of the macro \tempcommand. At the moment of defining the macro \nmerge TeX just sees the token \tempcommand.

When \nmerge is carried out and thus \tempcommand is carried out as well and delivers hashes and digits, TeX will not see a connection between these hashes and digits and the parameter text of the macro \nmerge at the time of defining the macro \merge. TeX will not take the hashes coming from expanding \tempcommand for denotations of arguments of \nmerge. These will just be some hashes and digits that go into the token-stream...

You need to get something like

\renewcommand\nmerge[#1] {%
    \noindent⟨replacement text/toplevel expansion of \tempcommand⟩
}%

Hereby \tempcommand needs to hold the right amount of hashes.

This is slightly tricky, but you were almost there with your attempt:

You can use tikz/pgffor's \foreach-loop for accumulating ##1##2... within the definition-text of a scratch-macro \tempcommand.

If you do this you need to know about \unexpanded:

While the definition-text of an \edef- or \xdef-definition is expanded, stuff wrapped in \unexpanded{...} is not expanded but the token \unexpanded and the pair of matching curly braces {...} surrounding that stuff go away.
A peculiarity of \unexpanded (and anything else that processes so-called ⟨general text⟩) is that TeX keeps expanding things until "seeing" the curly opening brace of the ⟨general text⟩. Thus, with \unexpanded{\foobar} expansion of \foobar is prevented while with \unexpanded\expandafter{\foobar} expansion of things that come from expanding \foobar is prevented, i.e., you get the so-called top-level-expansion of \foobar. This is because after \unexpanded TeX keeps expanding things until "seeing" the curly opening brace of the ⟨general text⟩ and hereby encounters \expandafter which in turn triggers top-level-expansion of the token \foobar right behind the curly opening brace. As soon as the toplevel-expansion of \foobar is delivered, expanding \expandafter itself (and thus removing that token from the token-stream) is done so that TeX can now "see" the curly opening brace belonging to \unexpanded's ⟨general text⟩.

If you do this you also need to know how TeX treats hashes (#) during macro-expansion:

  • A single hash trailed by one of the digits 1..9 in the macro definition denotes an argument of the macro.
  • If in the definition-text of a macro a hash is not trailed by a digit but is trailed by another hash, these two consecutive hashes are not taken for something that denotes an argument of that macro. During expansion of the macro these two hashes collapse into a single hash.
    E.g., with \def\foobar#1{#####1} doing \foobar{X} yields ##X: The first and the third hash each are trailed by another hash, namely the second/fourth hash - this collapses into single hashes that get delivered. The fifth hash is not trailed by another hash but is trailed by the digit 1 - this denotes the 1st argument of the macro \foobar.
    When nesting macro definitions inside macro definitions you can/need to use hash-doubling with those hashes that belong to denotations of macro-arguments of inner macro definitions.
  • Carrying out an \edef- or \xdef-assignment goes along with expanding the tokens that form the definition-text of the macro. Hereby hashes nested between \unexpanded{...} or coming from \the-expansion of a token-register get doubled (and the token \unexpanded and the curly braces are removed). This is a nice features because this way you can use \unexpanded for ensuring that you get as many pairs of hashes into the definition-text of the macro as you had single hashes between \unexpanded{...}. During expansion of the macro each of these pairs of hashes collapses into a single hash so that after expansion you get the same amount of hashes as you had in the definition-text of the macro between \unexpanded{...}.
  • \foreach defines a temporary macro from the argument that contains the tokens that shall be carried out repeatedly. Expanding that macro yields halving the amounts of consecutive hashes contained in that argument.

Summa summarum:

Expanding \tempcommand shall yield something like #1#2....
Thus the definition-text of \tempcommand is to consist of s.th. like ##1##2... so that each pair of consecutive hashes can collapse into a single hash when expanding \tempcommand.
Directives for defining \tempcommand are within the argument of a \foreach-loop so that hashes need to be doubled once more because \foreach defines a scratch-macro from that argument during whose expansion amounts of consecutive hashes get halved.
Everything comes from expanding the macro \nmergeinit which implies the need of doubling hashes yet once more.
All in all hashes need to be doubled three times. Doubling hashes three times outgoing from a single hash yields eight consecutive hashes.
In order to compensate the halving of amounts of hashes when in the \foreach-loop expanding \tempcommand, the expansion of \tempcommand needs to be wrapped between \unexpanded{...}.

So here is the code using \foreach for accumulating ##1##2... within the definition-text of \tempcommand:

\documentclass{article}
\usepackage{tikz}

\newcommand\nmergeinit[1]{%
    \gdef\tempcommand{}%
    \foreach \i in {1,...,#1}{%
        \xdef\tempcommand{%
           \unexpanded\expandafter{\tempcommand}########\i
        }%
    }%
    \providecommand\nmerge{}%
    \xdef\tempcommand{%
      \unexpanded{\renewcommand\nmerge[#1]}{\unexpanded\expandafter{\tempcommand}}%
    }%
    \tempcommand
}%

\begin{document}

\nmergeinit{6}
\nmerge{12}{34}{56}{78}{90}{12} \\
\nmergeinit{5}
\nmerge{hello }{nice }{to }{meet }{you} \\
\nmergeinit{4}
\nmerge{latex }{is }{so }{hard}

\end{document}

Using expl3, s.th. like the following might do the trick—x-expansion of \exp_args:Nnx requires hash-doubling. That's why \__ally_hashprepend:n is defined to deliver two hashes prepended to the number of the argument:

\documentclass{article}

\ExplSyntaxOn
\cs_new:Npn \nmerge #1 { #1 }
\cs_new:Nn \__ally_hashprepend:n { #### #1 }
\NewDocumentCommand{\nmergeinit}{m}
 {
  \exp_args:Nnx
     \use:nn 
     { \cs_set:Npn \nmerge }
     { \int_step_function:nN { #1 } \__ally_hashprepend:n
        { \int_step_function:nN { #1 } \__ally_hashprepend:n }
     }
 }
\ExplSyntaxOff

\begin{document}

\nmergeinit{6}
\nmerge{12}{34}{56}{78}{90}{12}

\nmergeinit{5}
\nmerge{hello }{nice }{to }{meet }{you}

\nmergeinit{4}
\nmerge{latex }{is }{so }{hard}

\end{document}

With these approaches you are restricted to concatenating at most nine arguments.

You can implement a tail-recursive mechanism where \romannumeral\nmergeamount000 is used for obtaining as many m as denoted by \nmergeamount and then tail-recursively consuming m and gathering another argument until all m are consumed:

\documentclass{article}

\csname @ifdefinable\endcsname\stopromannumeral{\chardef\stopromannumeral=`\^^00}%
\newcommand\firstoftwo[2]{#1}%
\newcommand\secondoftwo[2]{#2}%

\newcommand*\nmergeamount{}%
\newcommand*\nmergeinit[1]{\edef\nmergeamount{\number\numexpr(#1)\relax}}%

\newcommand*\nmerge{%
  \romannumeral\expandafter\nmergeloop\expandafter{\romannumeral\nmergeamount000}{}{}%
}%
\newcommand\nmergeloop[3]{%
  \ifx\relax#1\relax\expandafter\secondoftwo\else\expandafter\firstoftwo\fi
  {\expandafter\nmergeloop\expandafter{\firstoftwo{}#1}}%
  {\expandafter\stopromannumeral\secondoftwo{}}%
  {#2#3}%
}%


\begin{document}

\nmergeinit{6}
\nmerge{12}{34}{56}{78}{90}{12} \\
\nmergeinit{5}
\nmerge{hello }{nice }{to }{meet }{you} \\
\nmergeinit{4}
\nmerge{latex }{is }{hard }{hard}

\nmergeinit{15}
% This strips braces from the first 15 of the 20 arguments:
\edef\test{%
  \nmerge{1 }{2 }{3 }{4 }{5 }{6 }{7 }{8 }{9 }{10 }{11 }{12 }{13 }{14 }{15 }{16 }{17 }{18 }{19 }{20 }%
}

{\ttfamily\string\test=\meaning\test}

\end{document}

enter image description here

1

I don't really see the point to dynamically (re)define \nmerge.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\nmergeinit}{m}
 {
  \cs_set_eq:Nc
   \ally_nmerge:w
   { \int_compare:nT { #1 > 4 } { ally_ } use:\prg_replicate:nn { #1 } { n } }
 }
\nmergeinit{1}

\NewDocumentCommand{\nmerge}{}
 {
  \noindent\ally_nmerge:w
 }

% already defined up to four arguments, we can generalize
\cs_new:Nn \ally_use:nnnnn { #1 #2 #3 #4 #5 }
\cs_new:Nn \ally_use:nnnnnn { #1 #2 #3 #4 #5 #6 }
\cs_new:Nn \ally_use:nnnnnnn { #1 #2 #3 #4 #5 #6 #7 }
\cs_new:Nn \ally_use:nnnnnnnn { #1 #2 #3 #4 #5 #6 #7 #8 }
\cs_new:Nn \ally_use:nnnnnnnnn { #1 #2 #3 #4 #5 #6 #7 #8 #9 }

\ExplSyntaxOff

\begin{document}

\nmergeinit{6}
\nmerge{12}{34}{56}{78}{90}{12}

\nmergeinit{5}
\nmerge{hello }{nice }{to }{meet }{you}

\nmergeinit{4}
\nmerge{latex }{is }{so }{hard}

\end{document}

We just use predefined commands that do the job. The expl3 kernel only defines up to \use:nnnn, so we can provide the missing ones. In case #1 is greater than 4 we need to access the new commands.

Just for fun, here's a version where the command is dynamically redefined.

The idea is to generate the replacement text and to store it in a token list variable. Then we can define a new function using a variant to \cs_new:Nn that takes as arguments a function name and a token list.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\nmergeinit}{m}
 {
  \tl_set:Nx \l_tmpa_tl { \int_step_function:nN { #1 } \__ally_generate:n }
  \cs_set:cV { __ally_nmerge: \prg_replicate:nn { #1 } { n } } \l_tmpa_tl
  \cs_set:Npx \nmerge
   {
    \noindent \exp_not:c { __ally_nmerge: \prg_replicate:nn { #1 } { n } }
   }
 }
\cs_new:Nn \__ally_generate:n { #### #1 }
\cs_generate_variant:Nn \cs_set:Nn { cV }

\nmergeinit{1} % initialize

\ExplSyntaxOff

\begin{document}

\nmergeinit{6}
\nmerge{12}{34}{56}{78}{90}{12}

\nmergeinit{5}
\nmerge{hello }{nice }{to }{meet }{you}

\nmergeinit{4}
\nmerge{latex }{is }{so }{hard}

\end{document}

We need four # in the function called for building the token list in the \int_step_function:nN loop; they will be reduced to two in the token list and a further reduction to one will happen when \cs_new:cV is being processed.

1

I'm not clear if this does what you want, but the xstring package has the command \StrRemoveBraces to remove braces and form a new string, which you can assign to a macro. You just need to add an extra set of braces.

enter image description here

\documentclass{article}
\usepackage{xstring}

\begin{document}

\StrRemoveBraces{{hello }{nice }{to }{meet }{you}}[\mysentence]
Here is my sentence: \mysentence.

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .