Most efficient way to generate every possible capitalization of a string?
Note quite idiomatic L3 but
\documentclass{article}
\def\zz#1{\xzz{}#1\relax}
\def\xzz#1#2#3\relax{%
\ifx\relax#3\relax
\zzdo{#1#2}%
\zzdo{#1\uppercase{#2}}%
\else
\xzz{#1#2}#3\relax
\xzz{#1\uppercase{#2}}#3\relax
\fi}
% define to do whatever
\def\zzdo#1{\fbox{#1} }
\begin{document}
\zz{abc}
\end{document}
You can do it for “arbitrary” strings. Well, not so arbitrary, because a 32 character long string will produce 2^32 items.
Anyway, here is the code. The trick is to use the binary representation of numbers: a 1 means “uppercase”, a zero or nothing means “keep case”.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\generate}{O{default}m}
{% #1 = name for a sequence, #2 = string
\kevinkeith_generate:nn { #1 } { #2 }
}
\NewDocumentCommand{\use}{O{default}+m}
{
\seq_map_inline:cn { l_kevinkeith_generate_#1_seq } { #2 }
}
\cs_new_protected:Nn \kevinkeith_generate:nn
{
\seq_clear_new:c { l_kevinkeith_generate_#1_seq }
\seq_clear:N \l__kevinkeith_generate_temp_seq
\int_step_inline:nnnn { 0 } { 1 } { \fp_eval:n { 2^(\tl_count:n{#2})-1 } }
{
\__kevin_keith_generate_case:xn { \int_to_bin:n { ##1 } } { #2 }
}
\seq_set_eq:cN { l_kevinkeith_generate_#1_seq } \l__kevinkeith_generate_temp_seq
}
\cs_new_protected:Nn \__kevin_keith_generate_case:nn
{
\tl_clear:N \l__kevinkeith_generate_case_tl
\int_step_inline:nnnn { 1 } { 1 } { \tl_count:n { #2 } }
{
\str_if_eq_x:nnTF { \tl_item:nn { #1 } { -##1 } } { 1 }
{
\tl_put_right:Nx \l__kevinkeith_generate_case_tl
{
\tl_upper_case:n { \tl_item:nn { #2 } { ##1 } }
}
}
{
\tl_put_right:Nx \l__kevinkeith_generate_case_tl
{
\tl_item:nn { #2 } { ##1 }
}
}
}
\seq_put_right:NV \l__kevinkeith_generate_temp_seq \l__kevinkeith_generate_case_tl
}
\cs_generate_variant:Nn \__kevin_keith_generate_case:nn { x }
\tl_new:N \l__kevinkeith_generate_case_tl
\seq_new:N \l__kevinkeith_generate_temp_seq
\ExplSyntaxOff
\begin{document}
\generate{abc}
\use{#1 }
\generate[four]{abcd}
\use[four]{#1 }
\end{document}
A much faster code that just prints one of the possible capitalization, given a number between 1 and 2 raised to the string length.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\capitalizestring}{mm}
{% #1 = index of capitalized string, #2 = string
% the index is between 1 and 2^{length of string}
\kevinkeith_capitalize:nn { #1 } { #2 }
}
\cs_new_protected:Nn \kevinkeith_capitalize:nn
{
\int_step_inline:nnnn { 1 } { 1 } { \tl_count:n { #2 } }
{
\str_if_eq_x:nnTF { \tl_item:fn { \int_to_bin:n { #1 - 1 } } { -##1 } } { 1 }
{
\tl_upper_case:n { \tl_item:nn { #2 } { ##1 } }
}
{
\tl_item:nn { #2 } { ##1 }
}
}
}
\cs_generate_variant:Nn \tl_item:nn { f }
\ExplSyntaxOff
\begin{document}
\capitalizestring{1}{abc}
\capitalizestring{2}{abc}
\capitalizestring{3}{abc}
\capitalizestring{4}{abc}
\capitalizestring{5}{abc}
\capitalizestring{6}{abc}
\capitalizestring{7}{abc}
\capitalizestring{8}{abc}
\capitalizestring{523}{abcdefghij}
\end{document}