3

Question refined considering the replies…

In macro \StrCut, if the first argument contains a “ç”, we get an error message. The same happens with ”\c{c}” or capital “Ç”. When replaced with a plain “c” there is no error. No error ever with XeLaTeX nor LuaLaTeX.

I beleive \noexpandarg does not allow the source string to be a macro name.

It works (no error) for other accented characters like "ã", "á", etc… It works for German "ß". It does not work for "ç". I admit it is not an error, but this particular behavior for "ç" seems odd to me!

Example triggering the error:

\documentclass{article}
\usepackage{xstring}
\begin{document}
  \newcommand{\myname}{João,is,good}
  \StrCut{\myname}{,}\partone\parttwo
  [\partone][\parttwo]
  \renewcommand{\myname}{Straße,is,good}
  \StrCut{\myname}{,}\partone\parttwo
  [\partone][\parttwo]
  \renewcommand{\myname}{Açai,is,not,good}
  \StrCut{\myname}{,}\partone\parttwo
  [\partone][\parttwo]
  \renewcommand{\myname}{Açai,is,good,but,not,good}
  \noexpandarg\StrCut{\myname}{,}\partone\parttwo
  [\partone][\parttwo]
\end{document}
4
  • 1
    did you mean % rather than ## here? I can't see how you can avoid an error from # in text? Commented Nov 18, 2021 at 20:27
  • 1
    This is not a bug, it is documented behaviour of xstring Commented Nov 18, 2021 at 20:32
  • But it is an odd behavior, working with some accented characters (á, ã) and not with others (ç). :( Commented Nov 18, 2021 at 21:55
  • well it says it passes the arguments through \edef by default. \edef will basically destroy most latex commands including accented characters. If some manage to survive that's by luck not design. (the package probably should use \protected@edef rather than \edef, but it doesn't as it is not written for latex) You can usually use expl3 functions rather than xstring, but it depends what your use case is. Oh I just noticed @egreg posted expl3 versions. Commented Nov 18, 2021 at 22:27

2 Answers 2

7

Not a bug. You may use \noexpandarg, but there are other ways.

You can reimplement most (all) of xstring in expl3. Here's \StrCut:

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\xStrCut}{mmmm}
 {
  % #1 = tokens
  % #2 = separator where to split at
  % #3 = macro where to store the first part
  % #4 = macro where to store the second part
  \joao_xstrcut:nnNN { #1 } { #2 } #3 #4
 }

\seq_new:N \l_joao_strcut_parts_seq

\cs_new_protected:Nn \joao_xstrcut:nnNN
 {
  \seq_set_split:Nnn \l_joao_strcut_parts_seq { #2 } { #1 }
  \tl_clear_new:N #3
  \tl_clear_new:N #4
  \seq_pop_left:NN \l_joao_strcut_parts_seq #3
  \tl_set:Nx #4 { \seq_use:Nn \l_joao_strcut_parts_seq { #2 } }
 }
\ExplSyntaxOff

\begin{document}

\xStrCut{Açai,is,good}{,}\partone\parttwo

[\partone][\parttwo]

\end{document}

enter image description here

A version where you can use a macro for the first argument. You need to use \xStrCut*, in this case. I think that overloading is bad.

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\xStrCut}{smmmm}
 {
  % #1 = optional *
  % #2 = tokens
  % #3 = separator where to split at
  % #4 = macro where to store the first part
  % #5 = macro where to store the second part
  \IfBooleanTF{#1}
   {
    \joao_xstrcut:VnNN #2 { #3 } #4 #5
   }
   {
    \joao_xstrcut:nnNN { #2 } { #3 } #4 #5
   }
 }

\seq_new:N \l_joao_strcut_parts_seq
\tl_new:N \l_joao_strcut_head_tl
\tl_new:N \l_joao_strcut_tail_tl

\cs_new_protected:Nn \joao_xstrcut:nnNN
 {
  \tl_if_exist:NF #3 { \tl_new:N #3 }
  \tl_if_exist:NF #4 { \tl_new:N #4 }
  \seq_set_split:Nnn \l_joao_strcut_parts_seq { #2 } { #1 }
  \seq_pop_left:NN \l_joao_strcut_parts_seq #3
  \tl_set:Nx #4 { \seq_use:Nn \l_joao_strcut_parts_seq { #2 } }
 }
\cs_generate_variant:Nn \joao_xstrcut:nnNN { V }
\ExplSyntaxOff

\begin{document}

\xStrCut{Açai,is,good}{,}\partone\parttwo

[\partone][\parttwo]

\newcommand{\mytext}{Açai,is,good}

\xStrCut*{\mytext}{,}\partone\parttwo

[\partone][\parttwo]

\xStrCut*{\parttwo}{,}\parttwo\partthree

[\parttwo][\partthree]

\end{document}

enter image description here

3
  • This new xStrCut does not work if the source string is in a macro. See the refined examples above. Thanks. Commented Nov 18, 2021 at 21:37
  • @JoãoLourenço I added a version that accepts a macro as the first argument.
    – egreg
    Commented Nov 18, 2021 at 22:04
  • Thanks @egreg. You made my day. :) Commented Nov 18, 2021 at 22:38
8

In luatex or xelatex ç is a simple character token like c, but in pdflatex it is a pair of tokens that expand to \c{c}. xstring by default passes its arguments through \edef which would break any such command but it has a \noexpandarg switch to prevent this.

\documentclass{article}
\usepackage{xstring}
\begin{document}
  \noexpandarg
  \StrCut{Açai,is,good}{,}\partone\parttwo % #### No error when "Acai"
  [\partone][\parttwo]
\end{document}

enter image description here

1
  • How can I use \noexpandarg with the source string in a macro? See refined example. Thanks! Commented Nov 18, 2021 at 21:30

You must log in to answer this question.

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