5

How to split token list by any char, like a raw document text?

For example, i have a code to bold first word in macro argument. Macro is correctly works for direct using from code, like \bfirst{word word word}, but my macro can't separate words if i use token list variable.

My code:

% XeLaTeX Document
\documentclass[a4paper]{extarticle}
\usepackage{polyglossia}
\setdefaultlanguage[spelling=modern]{russian} 
\defaultfontfeatures{Ligatures={TeX},Renderer=Basic}
\setmainfont{Arial}

\usepackage{expl3}
\ExplSyntaxOn

    % Bold first word in macro argument
    \seq_new:N \l_mytest_bstring_seq
    \tl_new:N  \l_mytest_bfirst_tl

    \NewDocumentCommand{\bfirst}{ m }
    {
        \seq_set_split:Nnn \l_mytest_bstring_seq { ~ } { #1 }
        \seq_pop_left:NN   \l_mytest_bstring_seq \l_mytest_bfirst_tl

        \textbf{\l_mytest_bfirst_tl} ~
        \seq_use:Nn \l_mytest_bstring_seq { ~ }
    }

    % TL can't be splitted?
    \tl_new:N  \l_test_example_tl
    \tl_set:Nn \l_test_example_tl {TL\ word~word\ word...}

    \NewDocumentCommand{\tlbfirst}{}
    {
        \par\bfirst{\l_test_example_tl}
        \par\bfirst{\tl_use:N \l_test_example_tl}
    }

\ExplSyntaxOff

\begin{document}
    \par\bfirst{Word word word...}
    \tlbfirst
\end{document}

Result:

Difference between commands

How to make same result for raw text and token list?

Daniel G
  • 65
  • 3

2 Answers2

7

This is a good example showing why complex expl3 code shouldn't be used in the body of \NewDocumentCommand; only initializations and general checks, but the bulk of the task should be deferred to an internal function.

\documentclass{article}

\usepackage{xparse}
\ExplSyntaxOn

% Bold first word in macro argument
\seq_new:N \l_mytest_bstring_seq
\tl_new:N  \l_mytest_bfirst_tl

\NewDocumentCommand{\bfirst}{ m }
 {
  \mytest_bfirst:n { #1 }
 }

\cs_new_protected:Npn \mytest_bfirst:n #1
 {
  \seq_set_split:Nnn \l_mytest_bstring_seq { ~ } { #1 }
  \seq_pop_left:NN   \l_mytest_bstring_seq \l_mytest_bfirst_tl

  \textbf{\l_mytest_bfirst_tl} ~
  \seq_use:Nn \l_mytest_bstring_seq { ~ }
}
% generate a variant of \mytest_bfirst:n
\cs_generate_variant:Nn \mytest_bfirst:n { V }

% TL can't be split?
\tl_new:N  \l_test_example_tl
\tl_set:Nn \l_test_example_tl {TL\ word~word\ word}

\NewDocumentCommand{\tlbfirst}{}
 {
  \mytest_bfirst:V \l_test_example_tl
 }

\ExplSyntaxOff

\begin{document}
\bfirst{Word word word}

\tlbfirst
\end{document}

In this way, the second user level macro can be defined in terms of \mytest_bfirst:V.

enter image description here

egreg
  • 1,121,712
  • I disagree with “expl3 code shouldn't be used in the body of \NewDocumentCommand except for passing control to an internal function”. It shouldn't be used when it shouldn't be used (like in this cases). But there are many times when the interface macro is not just passing an argument to an internal macro but rather do some checks and more that (in my opinion, shouldn't be inside an expl3 macro because it doesn't belong to that level). It's just that I think that sentence is not good as a general rule. – Manuel Nov 12 '14 at 15:24
  • 1
    @Manuel I reworded the paragraph. – egreg Nov 12 '14 at 15:31
4

You want an x variant to expand the argument before splitting

enter image description here

\documentclass[a4paper]{extarticle}
\usepackage{polyglossia}
\setdefaultlanguage[spelling=modern]{russian} 
\defaultfontfeatures{Ligatures={TeX},Renderer=Basic}
\setmainfont{Arial}

\usepackage{expl3}
\ExplSyntaxOn
   \cs_generate_variant:Nn \seq_set_split:Nnn {Nnx}
    % Bold first word in macro argument
    \seq_new:N \l_mytest_bstring_seq
    \tl_new:N  \l_mytest_bfirst_tl

    \NewDocumentCommand{\bfirst}{ m }
    {
        \seq_set_split:Nnx \l_mytest_bstring_seq { ~ } { #1 }
        \seq_pop_left:NN   \l_mytest_bstring_seq \l_mytest_bfirst_tl

        \textbf{\l_mytest_bfirst_tl} ~
        \seq_use:Nn \l_mytest_bstring_seq { ~ }
    }

    % TL can't be splitted?
    \tl_new:N  \l_test_example_tl
    \tl_set:Nn \l_test_example_tl {TL\ word~word\ word...}

    \NewDocumentCommand{\tlbfirst}{}
    {
        \par\bfirst{\l_test_example_tl}
        \par\bfirst{\tl_use:N \l_test_example_tl}
    }

\ExplSyntaxOff

\begin{document}
    \par\bfirst{Word word word...}
    \tlbfirst
\end{document}

Note this splits on a space (~) not control spaces (\) so TL\ Word is a single word.

David Carlisle
  • 757,742