8

I would like to extract the first character. Using xstring's \StrChar works fine for simple cases. However, when the paramter has an additional brace group, I need some expansion magic to get that to work.

My naive attemps to 1) Test the first char with \IfBeginWith{#1}{\{}{}{} and 2) use \fullexpandarg didn't resolve this issue.

The MWE below produces

enter image description here

where as rhe desired output is a for both cases.

Related Questions:

Code:

\documentclass{article}
\usepackage{xstring}

\newcommand*{\ExtractFirstChar}[1]{%
    %% #1 = string to extract first char from
    %\fullexpandarg
    %\IfBeginWith{#1}{\{}{%
    %    \StrChar{#1}{2}[\FirstChar]%
    %}{%
        \StrChar{#1}{1}[\FirstChar]%
    %}%
    First char of '#1' is '\FirstChar'\par
}

\begin{document}
  \ExtractFirstChar{abc}
  \ExtractFirstChar{{a,b,c}}
\end{document}
4
  • {a,b,c} IS the first token. \detokenize{#1} gives an interesting result, but not a. Commented Jan 5, 2018 at 3:44
  • @JohnKormylo: Hmmm, that would make an interesting question. But, I don't want the first token, I want the first character. Commented Jan 5, 2018 at 5:00
  • what is the first character of {\'{e}abc} or {éfg} or \textbf{x}yz or \hspace{1em}xyz ? neither "first" nor "character" are well defined terms here. Commented Jan 5, 2018 at 8:47
  • @DavidCarlisle: Good point. But \StrRemoveBraces seems to work for my case. Commented Jan 5, 2018 at 10:10

2 Answers 2

7

You should use the \StrRemoveBraces before \StrChar:

\newcommand*{\ExtractFirstChar}[1]{%
    \StrRemoveBraces{#1}[\FirstChar]%
    \StrChar{\FirstChar}{1}[\FirstChar]%
    First char of '#1' is '\FirstChar'\par
}
1
  • Welcome to TeX.SE. Thanks for that. I was not aware of StrRemoveBraces as it is not listed in the Chapter 2. I should have read the remainer of the document. Commented Jan 5, 2018 at 10:08
2

Assuming your input only contains (non TeX special) ASCII characters and braces:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\firstchar}{sm}
 {
  \IfBooleanTF{#1}
   {
    \grill_firstchar:V #2
   }
   {
    \grill_firstchar:n { #2 }
   }
 }

\cs_new:Nn \grill_firstchar:n
 {
  \int_compare:nTF { \tl_count_tokens:f { \tl_head:n { #1 } } > 1 }
   {% we have to redo
    \grill_firstchar:f { \tl_head:n { #1 } }
   }
   {% just one token
    \tl_head:n { #1 }
   }
 }
\cs_generate_variant:Nn \tl_count_tokens:n { f }
\cs_generate_variant:Nn \grill_firstchar:n { V, f }

\ExplSyntaxOff

\begin{document}

\firstchar{abc} should print ``a''

\firstchar{{a,b,c}} should print ``a''

\firstchar{{{a},b,c}} should print ``a''

\newcommand\test{{{a}},b,c}

\edef\result{\firstchar*{\test}} \result\ should print ``a''

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .