1

I am in the process of writing a macro which takes a 4 digit hex value and does something based on the input. I want to achieve, that a user can use uppercase or lowercase characters for the hex code. What already works is:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand{\actionForHEX}{m}{%
    \str_case:nnF {#1}
    {
        {E085} {This is E085}
        {E086} {This is E086}
    }
    {Unknown}
}
\ExplSyntaxOff

\begin{document}
Works: \actionForHEX{E085}

Does not work: \actionForHEX{e085}
\end{document}

So in principal I can define actions, but I do not understand the use of \str_flipcase:n to allow the case to work for lowercase as well.

Based on Expandable case insensitive switch case for string comparison I tried something, but this had no success at all:

\ExplSyntaxOn
\NewDocumentCommand{\actionForHEX}{m}{%
    \str_case_e:nn { \str_foldcase:e { #1 } }
    {
        {E085} {This is E085}
        {E086} {This is E086}
    }
}
\ExplSyntaxOff

Ok, based on your input I tried my luck again, but it seems I still don't understand something. This is my new approach:

\documentclass{article}

\usepackage{expl3,xparse}

\ExplSyntaxOn
\NewDocumentCommand{\actionForHEX}{m}{%
    \str_case:nnF { \str_foldcase:n { #1 } }
    {
        {e085} {This~is~E085}
        {e086} {This~is~E086}
    }
    {Cannot~find~it}
}
\ExplSyntaxOff

\begin{document}
Does not work: \actionForHEX{E085}

Does not work: \actionForHEX{e085}
\end{document}

This results in Canot find it for both calls of \actionForHEX

  • 1
    Shouldn't your test cases be e085 and e086, resp.? – cgnieder May 11 at 3:59
  • 1
    What cgnieder says: With \str_foldcase you case-fold the input, now your comparison text must be case-folded as well. Case folding is largely based on lowercase, so you need to compare against e085 and e086. If you want to use \str_foldcase:e you'll need \cs_generate_variant:Nn \str_foldcase:n { e } as in the linked answer. You probably also want to write This~is~E085 to get spaces between the words. – moewe May 11 at 4:52
  • @moewe Looks like an answer to me – Joseph Wright May 11 at 8:35
  • I actually don't need to expand macros here, I will only use straight inputs. I attached a new approach, but this makes it worse, not better, I don't get, why. Do I need \str_case_e:nnF {\str_foldcase:n{#1}} ? This results in an undefined control sequence for \actionForHEX – TobiBS May 11 at 10:08
  • @TobiBS Yes, but you do need to expand \str_foldcase:n, otherwise the comparison will be between the literal strings \str_foldcase:n{e085} and e085. Try \exp_args:Ne \str_case:nnF { \str_foldcase:n { #1 } } – Phelype Oleinik May 11 at 11:51
4

As explained in the comments by cgnieder you need to compare against e085 and e086, respectively, since you are comparing against the case-folded input (\str_foldcase:n { #1 }). Broadly speaking, case folding is based on lowercase, so the input E085 gets folded into e085 and that's what you need to compare against.

Because we apply a macro to the input, we can't directly compare the strings with as normal n arguments. We need to make sure that \str_foldcase:n { #1 } is expanded first.

This can be done as in Skillmon likes topanswers.xyz's answer to Expandable case insensitive switch case for string comparison with \str_case_e:nn

\ExplSyntaxOn
\NewDocumentCommand{\actionForHEX}{m}{%
  \str_case_e:nn { \str_foldcase:n { #1 } }
    {
        {e085} {This~is~E085}
        {e086} {This~is~E086}
    }
}
\ExplSyntaxOff

That command will fully expand all involved strings with the new e-type expansion. (So \str_foldcase:n { #1 } is expanded, which is nice. And e085 and e086 are expanded as well, which is a bit pointless).

We can avoid the the expansion of e085 and e086 by generating the en-variant of \str_case:nn, which only expands \str_foldcase:n { #1 }

\ExplSyntaxOn
\cs_generate_variant:Nn \str_case:nn { e }

\NewDocumentCommand{\actionForHEX}{m}{%
  \str_case:en { \str_foldcase:n { #1 } }
    {
        {e085} {This~is~E085}
        {e086} {This~is~E086}
    }
}
\ExplSyntaxOff

If you are using an old system where e-type expansion is not available, you can try x-type expansion.

\documentclass{article}
\usepackage{expl3,xparse}

\ExplSyntaxOn
\cs_generate_variant:Nn \str_case:nn { x }

\NewDocumentCommand{\actionForHEX}{m}{%
  \str_case:xn { \str_foldcase:n { #1 } }
    {
        {e085} {This~is~E085}
        {e086} {This~is~E086}
    }
}
\ExplSyntaxOff

\begin{document}
\actionForHEX{E085}

\actionForHEX{e085}

\actionForHEX{E086}

\actionForHEX{e086}
\end{document}

This is E085//This is E085//This is E086//This is E086

On older systems \str_fold_case:n (introduced before November 2016, see l3news10) may work instead of \str_foldcase:n (which replaced \str_fold_case on 2019-11-26).


If you want to include an F non-matching branch at the end, it is better to generate the variants with \prg_generate_conditional_variant:Nnn (thanks to Phelype Oleinik for explaining that in the comments). For e-type expansion that would look as follows

\documentclass{article}
\usepackage{expl3,xparse}

\ExplSyntaxOn
\prg_generate_conditional_variant:Nnn \str_case:nn { e } { F }

\NewDocumentCommand{\actionForHEX}{m}{%
  \str_case:enF { \str_foldcase:n { #1 } }
    {
        {e085} {This~is~E085}
        {e086} {This~is~E086}
    }
    {Not~matched}
}
\ExplSyntaxOff

\begin{document}
\actionForHEX{E085}

\actionForHEX{e085}

\actionForHEX{E086}

\actionForHEX{e086}

\actionForHEX{E087}
\end{document}

It would be analogous for x-type expansion (and possibly \str_fold_case:n on older systems).

| improve this answer | |
  • Thanks @moewe, I am still a total newbie to expl3 and this helped me a lot to understand. I was now also able to expand your solution to a variant with a false tree: \ExplSyntaxOn \cs_generate_variant:Nn \str_case:nnF {xn} \NewDocumentCommand{\actionForHEX}{m}{% \str_case:xnF {\str_fold_case:n{#1}} { {e085} {This~is~E085} {e086} {This~is~E086} } {Alternative} } \ExplSyntaxOff – TobiBS May 12 at 11:46
  • @TobiBS The code you show should work (it does for me) however for branching conditionals you should use \prg_generate_conditional_variant:Nnn \str_case:nn { x } { F } instead. The first argument is the function without the conditionals in the signature, the second is the list of variants (same as for \cs_generate_variant:Nn), and the third is the list of branching conditionals. Note also that trailing n and N are redundant when generating variants and can be omitted. – Phelype Oleinik May 12 at 12:32
  • @PhelypeOleinik So prg_generate_conditional_variant is benefitial, because it does not expand the false clause, is that the point? Does this change the line \str_case:xnF {\str_fold_case:n{#1}}? – TobiBS May 13 at 11:14
  • @TobiBS I'm not sure I understand your question... Using \cs_generate_variant:Nn in a conditional function like \str_case:nnF works because of how it's implemented (and that's probably not going to change), but it's conceptually incorrect. Since \str_case:nnF is a conditional, you should use \prg_generate_conditional_variant:Nnn (which also makes it easier if you want to define also the T, TF, and p forms). But as I said, the code you posted in your first comment should work as well... – Phelype Oleinik May 13 at 11:55
  • 1
    @TobiBS Yeah, expl3 has advanced quite a lot in the past few years, so 2017 is rather outdated. – Phelype Oleinik May 13 at 14:57

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.