这是一些代码。

\documentclass{article}

\usepackage{xstring}

\begin{document}

\def\xloop#1{%
  \ifx\relax#1
    \else

     **\IFInteger{#1}{first integer is here.}** % need to be modified

      \expandafter\xloop% 
  \fi}

\def\test#1{\xloop#1\relax}

\test{abc3de5f}

\end{document}


5 个回答
5

此答案依赖于以下事实:数字 0-9 在 ASCII 表上按顺序位于第 48 和第 57 个位置之间(含)。紧接在 之前的位置0包含/,而紧接在 之后的位置9包含:

我们利用 TeX 语法,即符号前的重音符(反引号)会生成符号的槽号(ASCII 值)。因此,我设置了两个\ifnum测试…第一个测试查看当前符号的槽是否超出了 的槽/,第二个测试检查当前符号的槽是否在 的槽之前:

如果这两个条件都为真,则符号的槽位属于整数槽位范围。否则,它不在该范围。

\documentclass{article}

\def\xloop#1{%
  \ifx\relax#1
    \else
%
      \ifnum`#1>`/ 
        \ifnum`#1<`:
           \def\next{#1 is first integer\\}%
        \else
          \def\next{#1 is not an integer\\\expandafter\xloop}
        \fi
      \else
        \def\next{#1 is not an integer\\\expandafter\xloop}
      \fi
      \next% 
  \fi}

\def\test#1{\xloop#1\relax}
\begin{document}
\test{abc3de5f}
\end{document}

3

  • 1
    你能解释一下这是什么意思吗?


    – 

  • 这可以检查变量名是否包含数字。


    – 

  • @XCN 我已根据 cfr 的要求添加了解释。


    – 

关于如何终止循环的原始问题:

如果您\xloop有终止的\relax。 假设您的输入从不包含\relax标记(这已经是您自己的循环的先决条件),您可以通过吞下所有内容来终止循环,直到\relax,您只需要注意,因为您吞下了 ,所以\fi您需要重新插入一个。 以下操作可以做到这一点(但随后相当于expl3我的另一个答案中更干净的解决方案):

\documentclass{article}

\usepackage{xstring}

\begin{document}

\def\xloop#1{%
  \ifx\relax#1%
    \else
     \IfInteger{#1}{\xloopDone}{}%
      \expandafter\xloop
  \fi}
\def\xloopDone#1\relax{\fi first integer was here}

\def\test#1{\xloop#1\relax}

\test{abc3de5f}

\end{document}

仅产生收益first integer was here,没有其他。

这是一个仅使用 TeX 原语的可扩展解决方案:

\def\xloop#1{%
   \ifx\relax#1\else
      \ifnum 2<1#1 \loopE \else non-integer:#1 \fi
      \expandafter \xloop
   \fi
}
\def\loopE #1\relax{\fi\fi}

\xloop abc3de0f\relax

\bye

测试是否#1为整数是通过 完成的\ifnum。有两种情况:

\ifnum 2<1x \loopE \else non-integer:x\fi

此测试为假,因为 2<1 不成立。处理 else-text。

\ifnum 2<10 \loopE \else non-integer:0\fi

此测试为真,因为 2<10(或 11、12 等)为真。宏\loopE执行最后工作:忽略下一个文本\relax并关闭两个打开的\if分支。

0

如果这只是为了检查是否包含数字,以下是一种相当快速的方法:

\documentclass{article}

\ExplSyntaxOn
\NewExpandableDocumentCommand\ifcontainsnum{mmm}
  { \xcn_if_contains_num:nTF {#1} {#2} {#3} }
\prg_new_conditional:Npnn \xcn_if_contains_num:n #1 { TF, T, F, p }
  {
    \str_map_function:nN {#1} \__xcn_if_contains_num:n
    \prg_return_false:
  }
\cs_new:Npn \__xcn_if_contains_num:n #1
  { \xcn_if_digit:nT {#1} { \str_map_break:n { \use_i:nn \prg_return_true: } } }
\prg_new_conditional:Npnn \xcn_if_digit:n #1 { TF, T, F, p }
  {
    \if_int_compare:w 1 < 1\exp_not:N#1 \exp_stop_f:
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
\ExplSyntaxOff

\begin{document}
\ifcontainsnum{abc}{yes}{no}

\ifcontainsnum{abc1}{yes}{no}

\ifcontainsnum{ab{c1}}{yes}{no}
\end{document}

由此得到noyesyes

为什么只做数字?

这里\defineclass提供了一种形式\str_case:nnF,因此可以测试循环中的当前项是否属于该类。

你可以通过 来\loopbreak停止循环。参见最后的例子。

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\stringloop}{mmmmm}
 {% #1 = string to test
  % #2 = class name (CN)
  % #3 = what to do if the item is in the class (YES)
  % #4 = what to do if the item is not in the class (NO}
  % #5 = what to do at the end if not stopped (END)
  \xcn_stringloop:ennnn {\tl_to_str:n {#1}} {#2} {#3} {#4} {#5}
 }

\cs_new:Nn \xcn_stringloop:nnnnn
 {
  \__xcn_stringloop:w {#2} {#3} {#4} {#5} #1 \q_nil
 }
\cs_generate_variant:Nn \xcn_stringloop:nnnnn {e}

\cs_new:Npn \__xcn_stringloop:w #1 #2 #3 #4 #5
 {% #1 = CN, #2 = YES, #3 = NO, #4 = END, #5 = current item in string
  \quark_if_nil:nTF {#5}
   {
    #4
   }
   {
    \__xcn_stringloop_item:nnnnn {#1} {#5} {#2} {#3} {#4}
   }
 }
\cs_new:Nn \__xcn_stringloop_item:nnnnn
 {% #1 = CN, #2 = current item in string, #3 = YES, #4 = NO, #5 = END
  \use:c {__xcn_stringloop_class_#1:nTF} {#2} {#3} {#4}
  \__xcn_stringloop:w {#1} {#3} {#4} {#5}
 }

\NewDocumentCommand{\defineclass}{mm}
 {% #1 = class name, #2 = members
  \cs_new:ce {__xcn_stringloop_class_#1:nTF}
   {
    \exp_not:N \str_case:nnF {##1}
     { \tl_map_function:nN {#2} \__xcn_stringloop_make_case:n }
     { ##3 }
   }
 }
\cs_new:Nn \__xcn_stringloop_make_case:n { {#1}{##2} }

\NewExpandableDocumentCommand{\loopbreak}{m}
 {
  #1 \__xcn_stringloop_break:w
 }
\cs_new:Npn \__xcn_stringloop_break:w #1 \q_nil {}

\NewExpandableDocumentCommand{\checkforTF}{mmmm}
 {
  \xcn_stringloop:ennnn {\tl_to_str:n {#1}} {#2} {\loopbreak{#3}} {} {#4}  
 }

\ExplSyntaxOff

\defineclass{digits}{0123456789}
\defineclass{unknowns}{xyz}

\begin{document}

\raggedright

\stringloop{abc3def5g}{digits}{DIGIT }{NONDIGIT }{END}

\bigskip

\stringloop{abc3def5g}{digits}{\loopbreak{DIGIT, STOP}}{NONDIGIT }{END}

\bigskip

\checkforTF{abc3def5g}{digits}{There's a digit}{There's no digit}

\bigskip

\checkforTF{abcdefg}{digits}{There's a digit}{There's no digit}

\bigskip

\edef\test{\checkforTF{abc3def5g}{digits}{There's a digit}{There's no digit}}
\texttt{\meaning\test}

\bigskip

\stringloop{abxcy}{unknowns}{(unknown)}{(parameter)}{}

\bigskip

\stringloop{abxc}{unknowns}{\loopbreak{(unknown)}}{(parameter)}{end}

\bigskip

\stringloop{abc}{unknowns}{\loopbreak{(unknown)}}{(parameter)}{end}

\end{document}