Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

It's very much glossed over in texdoc interface3

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \Digits { m m }{
  \group_begin:
    \char_set_catcode_active:N ;
    \char_set_catcode_active:N .

    \def;{,\;}
    \def.{\dots}

    \langle #1 \rangle \sb #2
  \group_end:
}
\ExplSyntaxOff

\begin{document}
Desired syntax:
  $\Digits{1,2,3;4,5,6;.;,7}{8}$

Desired output:
  $\langle 1,2,3, \; 4,5,6, \; \dots, \; 7 \rangle_8$
\end{document}

I will be doing fancy things with the comma list at a later point (using l3clist), but I'd like to get this syntax working first.

I imagined that this should work based on the UK TeX FAQ article, but I keep getting the following error:

ERROR: Missing control sequence inserted.

--- TeX said ---
<inserted text> 
                \inaccessible 
l.18 $\Digits{1,2,3;4,5,6;.;,7}{8}
                                  $
--- HELP ---
This is probably caused by a \newcommand, \renewcommand, \newlength,
or \newsavebox command whose first argument is not a command name.

Per cgnieder's comment, perhaps the following approach would work:

\NewDocumentCommand \Digits { s m m } {
  \group_begin:
    \seq_set_split:Nnn
      \l_digit_seq
      { #2 }
      { \IfBooleanTF { #1 } { } { , } }

    \char_set_catcode_active:N ;
    \char_set_catcode_active:N .

    \def;{,\;}
    \def.{\dots}

    \real_digits:nn
}

\cs_new:Npn \real_digits:nn #1 #2 {
  \langle #1 \rangle \sb #2
  \group_end:
}
\ExplSyntaxOff

but alas, it does not.

share|improve this question
    
You can't change the catcode of tokens after they've been grabbed as argument... there must be questions on this already somewhere... –  cgnieder Jun 13 at 19:40
    
Perhaps I can change it then to \NewDocumentCommand\Digits{}{(catcode stuff)\real_digits:nn? See edit. –  Sean Allred Jun 13 at 19:42
    
Given my LaTeX3 knowledge, I would use something like \tl_replace_all:Nnn, which is “easier” (at least to me). Is there a reason why this wouldn't work? –  Manuel Jun 13 at 20:25
    
@Manuel that is indeed much more straightforward as far as readability goes… leave it to me to make things complicated! –  Sean Allred Jun 13 at 20:38

1 Answer 1

up vote 9 down vote accepted

It's no different from usual TeX programming; category codes are fixed at the moment the definition is stored, and in your definition ; and . have category code 12.

The procedure requires using \tl_to_lowercase:n in order to obtain the requested characters as active, while being able to use them in the replacement text.

Here's a possible implementation, with a generic activation function; the definition of \Digits shouldn't have parameters, in order to avoid absorbing the arguments after activating the characters.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn

\group_begin:
\char_set_catcode_active:N \^^@
\cs_new:Npn \sean_active_define:NN #1 #2
 {
  \group_begin: 
  \char_set_lccode:nn { `^^@ } { `#1 }
  \tl_to_lowercase:n
   {
    \group_end:
    \cs_set_eq:NN ^^@
   }
   #2 % the replacement text is better outside \tl_to_lowercase:n
   \char_set_catcode_active:N #1
}
\group_end:

\NewDocumentCommand \Digits { }
 {
  \group_begin:
  \sean_active_define:NN ; \__sean_active_semicolon:
  \sean_active_define:NN . \__sean_active_period:
  \sean_digits:nn
 }

\cs_new_protected:Npn \sean_digits:nn #1 #2
 {
  \langle #1 \rangle\sb{#2}
  \group_end:
 }

\cs_new_protected:Npn \__sean_active_semicolon: { ,\; }
\cs_new_protected:Npn \__sean_active_period: { \dots }
\ExplSyntaxOff

\begin{document}
\makebox[2.5cm][l]{Desired syntax:}
  $\Digits{1,2,3;4,5,6;.;7}{8}$

\makebox[2.5cm][l]{Desired output:}
  $\langle 1,2,3, \; 4,5,6, \; \dots, \; 7 \rangle_8$
\end{document}

enter image description here

You may avoid activating the characters by making them “math active”, which doesn't require absorbing the arguments in two stages.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn

\group_begin:
\char_set_catcode_active:N \^^@
\cs_new:Npn \sean_math_active_define:NN #1 #2
 {
  \group_begin: 
  \char_set_lccode:nn { `^^@ } { `#1 }
  \tl_to_lowercase:n
   {
    \group_end:
    \cs_set_eq:NN ^^@
   }
   #2 % the replacement text is better outside \tl_to_lowercase:n
   \char_set_mathcode:nn { `#1 } { "8000 }
}
\group_end:

\NewDocumentCommand \Digits { m m }
 {
  \group_begin:
  \sean_math_active_define:NN ; \__sean_active_semicolon:
  \sean_math_active_define:NN . \__sean_active_period:
  \langle #1 \rangle\sb{#2}
  \group_end:
 }

\cs_new_protected:Npn \__sean_active_semicolon: { ,\; }
\cs_new_protected:Npn \__sean_active_period: { \dots }

\ExplSyntaxOff

\begin{document}
\makebox[2.5cm][l]{Desired syntax:}
  $\Digits{1,2,3;4,5,6;.;7}{8}$

\makebox[2.5cm][l]{Desired output:}
  $\langle 1,2,3, \; 4,5,6, \; \dots, \; 7 \rangle_8$
\end{document}

NOTE: I changed slightly the implementation, making it a bit more powerful and easier to manage; now it's easy to define local active characters also with arguments.

share|improve this answer
    
Thanks, egreg! It seems the \group_begin: \tl_to_lowercase:n { \group_end: ... } pattern is a common one. Is there any place that comes to mind that explains what is going on here specifically? –  Sean Allred Jun 13 at 19:50
1  
    
@SeanAllred I changed slightly the code, making it easier to manage and perhaps to read. –  egreg Jun 13 at 20:36
    
If you use \cs_set_eq:NN inside \tl_to_lowercase shouldn't \sean_math_active_define:Nn be :NN? In case the second argument is not a single token \cs_set_eq:NN won't work as expected? Or am I missing something? –  Manuel Jun 13 at 21:01
1  
N.B. the \char_(g)set_active:Npn and \char_(g)set_active_eq:NN function in l3candidates; how functions in that module get "promoted" into the main codebase is largely from whether people find them useful — so if you start using them, they'll most probably stick around :) –  Will Robertson Jun 14 at 3:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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