As I mentioned before, this is officially "undefined behavior", use collcell package then process the data as usual. But this is an answer anyway.
You must understand how \halign primitive works and all the 3 kinds of brace hacks do (TeXbook appendix D, or Understanding Brace Hacks / Showcase of brace tricks: }, \egroup, \iffalse{\fi}, etc.) to understand this answer.
First, make a MWE:
\documentclass{article}
\begin{document}
\ExplSyntaxOn
\protected\def\test {\group_align_safe_begin: \testb}
\protected\def\testb #1 {\group_align_safe_end: #1}
\halign{\test\ignorespaces# \cr
123 \cr}
\ExplSyntaxOff
\end{document}
What's going on here?
the \test macro, as defined, will do the following...
- expand
\group_align_safe_begin:
- grab the
\ignorespaces token
- expand
\group_align_safe_end:
Problem arises because, while it does that...
- expand
\group_align_safe_begin: → increase the master counter by 1
- grab the
\ignorespaces token → runs into the end of the u part of the template. TeX marks that the target master counter should be 1 at the end of the alignment entry
- expand
\group_align_safe_end: → return the master counter. Too late.
when the & is seen, it will rightfully complain that the current master counter value is 0, while it should be 1 to properly end the alignment entry.
Here the problem is the explicit adjustment of the master counter, which is obviously desired in most common cases.
(side note, in this particular MWE you can avoid touching the # part with
\halign{\test\ignorespaces\empty# \cr
123 \cr}
but this is not applicable if you want to peek into the entry itself)
(by the way, the \expandafter you put before \test actually have no effect as \ignorespaces is not expandable; nevertheless it makes TeX "see" the \ignorespaces token and that "touches" the # part, thus set the target master counter value to 0 instead of 1)
Nevertheless you can choose to "opt out" of it by "undo" the effect (highly not recommended):
\protected\def\test{\group_align_safe_end: \testa} % remember to protect this, because the start of an alignment entry is initially expanded to look for e.g. \omit
\NewDocumentCommand\testa{m}{\group_align_safe_begin: #1}
It does work in the \halign example above.
Needless to say you can find an example where disabling alignment-protect is harmful.
For things like \peek_analysis_map_inline:n protecting is obviously useful (https://github.com/latex3/latex3/issues/1090),
for things like clist_map_ etc. it's kind of useful,
for argument grabbing, I'm not sure. (maybe grabbing & inside an optional argument counts.)
There's this one (although a little contrived... who needs to take the \cr as input anyway...?)
\documentclass{article}
\begin{document}
\ExplSyntaxOn
% the following 4 lines are equivalent to the simple \protected\def below
%\protected\def\test{\group_align_safe_end: \testa} % remember to protect this, because the start of an alignment entry is initially expanded to look for e.g. \omit
%\NewDocumentCommand\testa{+m}{\group_align_safe_begin:
% #1
%}
\protected\def\test #1{#1}
\halign{# \cr
\test \cr}
\ExplSyntaxOff
\end{document}
\def\test#1#2{\newcommand{\temp}[1][default]{##1}#2#1\temp}? bur as with the first form\expandafterapplied to arbitrary tokens may not work as you expect – David Carlisle Jul 24 '22 at 13:13\test{foo}[bar]that might be omitted:\test{foo}– antshar Jul 24 '22 at 13:15\NewDocumentCommand{\test}{mm}{so two m ?? – David Carlisle Jul 24 '22 at 13:18m O{} m, but the question is about\NewDocumentCommandin the first space so it's not necessarily to mention that. – antshar Jul 24 '22 at 13:20NewDocumentCommand{\test}{mo}{that is completely different question as, as explained last time, you can not use NewExpandableDocumentCommand for a final o argument – David Carlisle Jul 24 '22 at 13:21\ignorespaceshave to be swallowed, thus I havem O{} mwhere the lastmis responsible for that. – antshar Jul 24 '22 at 13:22@{...}anyway!? Use thecollcellpackage to correct the cell content, then you can do whatever with it. (which does peek ahead and some\ignorespaceshack; but then it's a "more famous" package so more likely to be correct) – user202729 Jul 24 '22 at 13:47\NewDocumentCommand— here what this post is about. – antshar Jul 24 '22 at 13:50\NewDocumentCommandmust behave like(\protected)\def, but I agree that this question might reveal a bug on\NewDocumentCommand-defined commands being non-align-safe or something. Although the point remains that you're invoking "undefined behavior" i.e. tabular environment does not support it by peeking ahead intabular@{...}, so it may not actually be a bug. – user202729 Jul 24 '22 at 13:54\NewDocumentCommandbehaves differently from\protected\defwithout invoking "undefined behavior". – user202729 Jul 24 '22 at 14:01