在 for 循环中提取两个字符串的字符

在 for 循环中提取两个字符串的字符

我有两个长度相等的字符串,假设为abcdef(实际上它们可以更长)。两个字符串都只包含字母a-zA-Z(没有数字,没有特殊字符等)。我需要从两个字符串中分别提取字符,并在我定义的另一个宏中成对使用它们。

例如对于两个字符串abcdef以及我定义的其他一些宏\printchar[2]{#1,#2},我希望能够将字符一对一对地传递到中\printchar,即

\printchar{a}{d}
\printchar{b}{e}
\printchar{c}{f}

也许是某种 for 循环。所以我想这个问题有两个方面:

  1. 如何从中提取字符逐个字符地输入等长字符串,并且
  2. 随后在宏内成对使用它们。(并且它应该循环遍历字符串中的所有字符)。

伪代码:

\documentclass[]{article}
\newcommand\printchar[2]{#1,#2}
\newcommand\foo[2]{% Takes in two strings
    % <begin loop>
    % Extracts out one character from both strings
    \printchar{#1}{#2}%
    % Continue loop until strings run out of characters
    % <end loop>
}

\begin{document}
    \foo{abc}{def} % Should print a,d,b,e,f
\end{document}

通过一些搜索,我思考也许该xstring包可以完成第一部分?但我不太清楚如何将其与 for 循环集成以实现我想要的效果。

答案1

没有任何软件包:

\documentclass[]{article}
\makeatletter
\newcommand\printchar[2]{#1,#2}
\def\parsefoo#1#2,#3#4|{%
    \ifx\relax#1\relax%
    \else%
        \ifx\relax#3\relax%
        \else%
            \printchar{#1}{#3}%
            \ifx\relax#2\relax%
            \else%
                \ifx\relax#4\relax%
                \else%
                    ,\edef\@footmp{#2,#4|}%
                    \expandafter\parsefoo\@footmp%
                \fi%
            \fi%
        \fi%
    \fi%
}
\newcommand\foo[2]{% Takes in two strings
    % <begin loop>
    % Extracts out one character from both strings
    \edef\@footmp{#1,#2|}%
    \expandafter\parsefoo\@footmp%
    %\printchar{#1}{#2}%
    % Continue loop until strings run out of characters
    % <end loop>
}
\makeatother

\begin{document}
    \foo{abc}{def} % Should print a,d,b,e,f
    haha
\end{document}

结果

答案2

当任一字符串用完项目时,循环将停止。

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\foo}{mmm}
 {% #1 is the macro to use, #2 is the first string, #3 is the second string
  \troy_foo:Nnn #1 { #2 } { #3 }
 }

\seq_new:N \l_troy_foo_first_seq
\seq_new:N \l_troy_foo_second_seq

\cs_new_protected:Nn \troy_foo:Nnn
 {
  % split the first string into items
  \seq_set_split:Nnn \l_troy_foo_first_seq { } { #2 }
  % split the second string into items
  \seq_set_split:Nnn \l_troy_foo_second_seq { } { #3 }
  % map over the two string
  \seq_mapthread_function:NNN \l_troy_foo_first_seq \l_troy_foo_second_seq #1
 }
\ExplSyntaxOff

\newcommand{\printchars}[2]{#1#2\par}

\begin{document}

\foo{\printchars}{abc}{def}

\end{document}

在此处输入图片描述

完全可扩展的变体:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\loopstrings}{mmm}
 {
  \troy_loopstrings:Nnn #1 { #2 } { #3 }
 }
\cs_new:Nn \troy_loopstrings:Nnn
 {
  \__troy_loopstrings:Nffff #1
   { \tl_head:n { #2 } } { \tl_head:n { #3 } }
   { \tl_tail:n { #2 } } { \tl_tail:n { #3 } }
 }

\cs_new:Nn \__troy_loopstrings:Nnnnn
 {
  \bool_lazy_or:nnF { \tl_if_empty_p:n { #2 } } { \tl_if_empty_p:n { #3 } }
   {
    #1{#2}{#3}
    \troy_loopstrings:Nnn #1 { #4 } { #5 }
   }
 }
\cs_generate_variant:Nn \__troy_loopstrings:Nnnnn { Nffff }
\ExplSyntaxOff

\newcommand{\printchars}[2]{#1#2\par}

\begin{document}

\loopstrings{\printchars}{abcd}{1234}

\loopstrings{\printchars}{abc}{1234}

\loopstrings{\printchars}{abcd}{123}

\end{document}

答案3

这是一个基于 LuaLaTeX 的解决方案。(与 @egreg 的答案的输出完全相同,因此没有单独的屏幕截图。)

%% to be compiled under LuaLaTeX
\documentclass{article}
\usepackage{luacode} 
\begin{luacode}
  function string_pair ( u , v )
    for i=1,string.len(u) do 
      tex.sprint ( string.sub (u,i,i) .. string.sub (v,i,i) .. "\\par" )
    end
  end
\end{luacode}
\newcommand\foo[2]{\directlua{string_pair(\luastring{#1},\luastring{#2})}}

\begin{document}
\foo{abc}{def}
\end{document} 

答案4

当我在玩弦乐的时候(循环遍历字符串)我还做了一个宏来循环两个字符串。但是,从我收到的回复来看,这似乎不是一个好的解决方案,因为它不使用尾部递归。另一方面,它的优点是易于理解,因此我把它放在这里。

\documentclass{article}

\begin{document}

\def\doubleloop<#1#2><#3#4>{%
  \ifx\relax#1 \else
    \ifx\relax#3 \else
      [#1,#3] 
      \doubleloop<#2><#4>
    \fi
  \fi}

\def\loopstrings#1#2{\doubleloop<#1\relax><#2\relax>}

\verb|\loopstrings{abcd}{1234}| \loopstrings{abcd}{1234}

\verb|\loopstrings{abc}{1234}| \loopstrings{abc}{1234}

\verb|\loopstrings{abcd}{123}| \loopstrings{abcd}{123}

\end{document}

在此处输入图片描述

这可以使用尾递归转换为宏:

\documentclass{article}

\begin{document}

\makeatletter
\def\doubleloop<#1#2><#3#4>{%
  \ifx#1\relax
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi
  {\doubleloopaux{#1}{#2}{#3}{#4}}%
}
\def\doubleloopaux#1#2#3#4{%
  \ifx#3\relax
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi
  {[#1,#3]\doubleloop<#2><#4>}%
}
\makeatother

\def\loopstrings#1#2{\doubleloop<#1\relax><#2\relax>}

\verb|\loopstrings{abcd}{1234}| \loopstrings{abcd}{1234}

\verb|\loopstrings{abc}{1234}| \loopstrings{abc}{1234}

\verb|\loopstrings{abcd}{123}| \loopstrings{abcd}{123}

\end{document}

相关内容