4

The goal is to have a macro with single argument, that looks at all tokens in turn and if it sees a lower-case letter it is wrapped in \texttt{<token>}. All other tokens are passed through untouched. I came as far as:

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new:Npn \lctt:n #1 { \tl_if_in:nnTF {abcdefghijklmnopqrstuvwxyzäüöß} {#1} {\texttt{#1}} {#1} }
\cs_new:Npn \demo:n #1 { \tl_map_function:nN {#1} \lctt:n }
\cs_new_eq:NN \demo \demo:n
\ExplSyntaxOff
\newcommand*{\hello}{hello}
\begin{document}
\demo{AbcDef\hello{\hello}GhiJ}

\demo{SS\texttt{S}Sbεa}

\demo{ }

\demo{}

\demo{\hello}
\end{document}

It works in the first case but the second use fails with

! Argument of \lctt:n has an extra }.

At the moment it eludes me where the difference between the two uses is.

Furthermore is there a better way to test whether a token contains a lower case letter then listing them exhaustively? (lccode?) With my approach if I want to include the small Greek letters I have to extend the list.

  • Are you with pdflatex, xelatex or lualatex? Are you using UTF-8? – egreg Jan 9 '16 at 22:45
  • What should the last call yield? – egreg Jan 9 '16 at 22:56
  • @egreg, lualatex and utf-8, the last call has one token, that is not a letter only on command sequence, it should go through untouched. – uli Jan 10 '16 at 8:35
  • As it stands the error is not surprising: you are mapping token-by-token and not allowing for the presence of macros in the argument (for example \texttt in the first example). Can you give us a detailed spec on the nature of the tokens to be handled: it's quite doable to deal with macros, spaces, ... but we'll need a bit more detail. For example, to pick up \texttt and skip it but expand \hello we need either an opt-in or opt-out list of macros to skip. – Joseph Wright Jan 10 '16 at 10:16
  • @Joseph only lower case letters matter, everything else can be passed through, no expansion. AöT\hello{\hello} contains one small letter thus A\texttt{ö}T\hello{\hello} is the desired result. EghF\texttt{s}D contains three but the third is hidden in the group token, so the desired result is E\texttt{g}\texttt{h}F\texttt{s}D. Just processing the first level, no expansion. – uli Jan 10 '16 at 10:27
2

You could try l3regex:

\documentclass{article}
\usepackage{fontspec}
\usepackage{xparse,l3regex}

\setmainfont{FreeSerif}
\setmonofont{FreeMono}

\ExplSyntaxOn
\NewDocumentCommand{\demo}{m}
 {
  \tl_set:Nn \l_uli_demo_tl { #1 }
  \regex_replace_all:NnN \c_uli_demo_repl_regex { \c{texttt}\cB\{\1\cE\} } \l_uli_demo_tl
  \tl_use:N \l_uli_demo_tl
 }
\regex_const:Nn \c_uli_demo_repl_regex { ([a-zäüößε]+) }
\ExplSyntaxOff

\newcommand*{\hello}{hello}

\begin{document}

\demo{AbcDef\hello{\hello}GhiJ}

\demo{SS\texttt{S}Sbεa}

X\demo{ }X

X\demo{}X

\demo{\hello}

\end{document}

enter image description here

2

The desired effect isn't given by \tl_map_inline:nn as this works on a TeX 'balanced text' (n-type argument`) basis. This means that for example

SS\texttt{S}Sbεa

has \texttt processed separately from its argument, and that the braces around {S} are lost.

We can arrange for a more careful (but slower) loop which can detect braces and spaces. There is some internal code in expl3 that does this in for example \tl_reverse:n, and there is a similar set up in \tl_lower_case:n. Using that might lead to something like

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_protected:Npn \uli_demo:n #1
  {
      \exp:w
      \__tl_act:NNNnn
        \__uli_demo_normal:nN
        \__uli_demo_group:nn
        \__uli_demo_space:n
        { }
        {#1}
  }
\cs_new:Npn \__uli_demo_normal:nN #1#2
  {
   \token_if_cs:NTF #2
      { \__tl_act_output:n {#2} }
      {
        \int_compare:nNnTF { `#2 } = { \char_value_lccode:n {`#2} }
          { \__tl_act_output:n { \texttt {#2} } }
          { \__tl_act_output:n {#2} }
      }
  }
\cs_new:Npn \__uli_demo_group:nn #1#2
  { \__tl_act_output:n { {#2} } }
\cs_new:Npn \__uli_demo_space:n #1
  { \__tl_act_output:n{ ~ } }

\cs_new_eq:NN \demo \uli_demo:n
\ExplSyntaxOff
\newcommand*{\hello}{hello}
\begin{document}
\demo{AbcDef\hello{\hello}GhiJ}

\demo{SS\texttt{S}Sbεa}

\demo{ }

\demo{}

\demo{\hello}
\end{document}

where I'm using the fact that lower case letters map to themselves (using the lccode value).

A non-expandable version of the loop used in the above is a bit more robust and can deal with some cases that we can't in the expandable version, but as the code already exists it seems easy enough just to 'go with it'. Also notice that I've not tried to cover UTF-8 input with pdfTeX: this can be done by checking for definitions equal to the 'lead off' of a UTF-8 sequence in inputenc, but again is extra work.

Note that this is using an internal function which might (and I think will) get reworked soon. If the approach looks useful I'll rework the above to avoid that: a bit more effort so I'll first wait for some feedback!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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