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

8
  • 1
    Shouldn't your test cases be e085 and e086, resp.?
    – cgnieder
    Commented May 11, 2020 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
    Commented May 11, 2020 at 4:52
  • @moewe Looks like an answer to me
    – Joseph Wright
    Commented May 11, 2020 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
    Commented May 11, 2020 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 } } Commented May 11, 2020 at 11:51

1 Answer 1

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).

6
  • 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
    Commented May 12, 2020 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. Commented May 12, 2020 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
    Commented May 13, 2020 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... Commented May 13, 2020 at 11:55
  • 1
    @TobiBS Yeah, expl3 has advanced quite a lot in the past few years, so 2017 is rather outdated. Commented May 13, 2020 at 14:57

You must log in to answer this question.

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