9

I want to convert to lowercase a token list that is composed by letter, digits and the control sequence \\. I try to use \str_lowercase:n but the control sequence is not covered also to text.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\lowertl}{m}{%
  \tl_set:Nn \l_tmpa_tl {#1}
  \str_lowercase:f {\tl_to_str:N \l_tmpa_tl}
}
\ExplSyntaxOff


\begin{document}
  \lowertl{This is my\\ Text}
\end{document}

The output running xelatex is:

this is my““ text

Is an easy way to iterate over tokens in a token list and lowercase only the letters?

  • The reason str_lower_case is failing is because it converts everything inside to catcode letter – apparently the lccode of \ is ". I would've imagined \cs_new:Nn \__lower_it:n { \tl_map_inline:nn {#1} { \token_if_letter:NT {##1} {\tl_lower_case:n} {##1}}} would work, but it gets tripped up by \\ all the same. (This is getting back into about where I stopped understanding TeX guts, so forgive any misconceptions that others will surely correct me on.) – Sean Allred Sep 1 '16 at 1:19
  • @SeanAllred There is no \token_if_letter:NT by default. Did you generate a variant? And you are not passing \tl_lower_case:n the argument it expects, I don't think. Also, I think this retains the \\ (or would) but strips the spaces. Am I misunderstanding? – cfr Sep 1 '16 at 2:29
  • @cfr It's definitely there – is your installation perhaps outdated? And I was trying to test tl_map_inline here – there are other points which ignore spaces (e.g. tl_head), but the docs are ambiguous for this one. It's possible tl_map won't work at all. (And yes, the way the expansion works out, tl_lower_case is still getting its argument.) – Sean Allred Sep 1 '16 at 2:32
  • @SeanAllred Thanks. I don't know. I just made it when I got errors with your code. And yes, I can see that it does get an argument but it seems not in the spirit of L3 to do it that way. And it definitely works. At least, my code works with my version of stuff. I assume it will still work with the updated version, though I don't know yet, obviously. – cfr Sep 1 '16 at 2:48
  • @cfr Yep, your solution works with my distribution, but I'd agree it seems a wacky way of going about it :) In the absence of other approaches, though… – Sean Allred Sep 1 '16 at 2:53
5

Update 2020-01-14

The LaTeX kernel now makes \\ robust out-of-the-box. When used with the latest expl3 function \text_lowercase:n, this works with no additional adjustments. The comment in the original answer about strings versus text remains valid: you are case-changing text.

Original answer

The function \str_lowercase:n is for making strings lower case, and is for programmatic data not for text. You want \text_lowercase:n. The only issue is that \\ is not engine robust and the implementation of \text_lowercase:n expects 'text' to be either character tokens, things which expand to character tokens or engine-robust commands. We can solve that by locally making \\ engine-robust:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand \LowerCase { m }
  {
    \group_begin:
      \cs_set_protected:Npx \\ { \exp_not:o \\ }
      \text_lowercase:n {#1}
    \group_end:
  }
\ExplSyntaxOff


\begin{document}
  \LowerCase{This is my\\Text}
\end{document}

If you make \\ robust globally then everything stays expandable

\documentclass{article}

\usepackage{etoolbox}
\robustify\\
\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand \LowerCase { m }
  { \text_lowercase:n {#1} }
\ExplSyntaxOff

\begin{document}
  \LowerCase{This is my\\Text}
\end{document}

Note that there is no need to store #1 in a token list variable in either case.

| improve this answer | |
  • The team are thinking about \\ at the moment! This may yet change :-) – Joseph Wright Sep 1 '16 at 7:35
  • I have to store #1 because is defined in a function and retrieved later. The token list is used as the text in a tikz multiline node; does rebustifying \\have any side effect? – TeXtnik Sep 1 '16 at 10:35
  • How would you conserve spaces in user input when you do need to manipulate the token list? (I think I need to do it as a string, though perhaps I'm mistaken about that.) Maybe I should ask a new question. – cfr Sep 1 '16 at 11:18
  • @JosephWright: I tried both approaches but it seems they don't work inside a \begin{tikzpicture}[overlay, remember picture] environment. – TeXtnik Sep 1 '16 at 13:01
  • @cfr There's some careful set up inside \tl_lower_case:n that preserves spaces. One can do that a few ways: wipet doubtless will have somewhere posted a short version of the idea or I can provide a longer one – Joseph Wright Sep 1 '16 at 13:07
1

This is not an expandable version (and I am not sure this is what is really requested)

The basic idea is to split the token at the places where \\ occurs, storing the parts in an \seq variable, change the case of the symbols in the list and glue the parts together, with \\ filled again.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\lowertl}{m}{
  \seq_set_split:Nnn \l_tmpa_seq {\\} {#1} 
  \seq_map_inline:Nn \l_tmpa_seq {
    \seq_put_right:Nx \l_tmpb_seq {\str_lowercase:n {##1}}
  }
  \seq_clear:N \l_tmpa_seq
  \seq_map_inline:Nn \l_tmpb_seq {
    \int_incr:N \l_tmpa_int
    \int_compare:nNnTF { \l_tmpa_int } < {\seq_count:N \l_tmpb_seq }
    {\seq_put_right:Nn \l_tmpa_seq { ##1 \\ } }
    {\seq_put_right:Nn \l_tmpa_seq { ##1} }% Don't add the \\
  }
  \seq_use:Nn \l_tmpa_seq {}
}
\ExplSyntaxOff


\begin{document}
\noindent\lowertl{This is my\\ Text @\\ FOO OTHER STUFF #}
\end{document}

enter image description here

| improve this answer | |

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.