是否有 TeX 宏(纯文本或 AmS-TeX)可以搜索特定字符串?具体来说,我想要一个宏,它是 if/then 宏的一部分,其形式为,如果给定的字符串 xyz 出现在单词中,则 ...,否则为其他内容。
答案1
答案2
这是( ) 和( )expl3
的副本。前者考虑了 catcode 的差异,而后者将所有内容视为 catcode-12(空格除外,空格为 catcode-10)。语法是。宏定义一个由 分隔的辅助,然后使用它来检查 是否包含。在表格单元格中以及对于空参数使用此宏可以提高安全性(有关实现详细信息,请参阅 的文档)。\tl_if_in:nn
\IfContainedIn
\str_if_in:nn
\StrIfContainedIn
\StrIfContainedIn{<string>}{<substring>}{<true>}{<false>}
<substring>
<string>
<substring>
l3tl
如果您使用带有 ε-TeX 的 TeX 引擎(\detokenize
需要从参数中生成字符串并进行稳健\IfEmpty
测试),那么:
\catcode`\@=11
\def\@firstoftwo#1#2{#1}
\def\@secondoftwo#1#2{#2}
\def\return@if@false{\expandafter\@secondoftwo\romannumeral}
\def\return@if@true{\expandafter\@firstoftwo\romannumeral}
\chardef\exp@end=0
%
\def\IfEmpty#1{%
\if\relax\detokenize{#1}\relax
\return@if@true
\else
\return@if@false
\fi\exp@end}
%
\def\IfContainedIn#1#2{%
\relax\iffalse{\fi
\def\if@contained@aux##1#2{}%
\expandafter\IfEmpty\expandafter{\if@contained@aux#1{}{}#2}%
{\return@if@false}{\return@if@true}%
\iffalse}\fi
\exp@end}
%
\def\StrIfContainedIn#1#2{%
\edef\@@tmpa{\noexpand\IfContainedIn
{\detokenize{#1}}{\detokenize{#2}}}\@@tmpa
{\return@if@true}{\return@if@false}%
\exp@end}
\catcode`\@=12
\StrIfContainedIn{hello}{el}{T}{F}
\StrIfContainedIn{hello}{le}{T}{F}
\bye
否则,如果您使用的是 Knuth 的 TeX,那么您需要一个 poorman 的\detokenize
:
\def\@firstoftwo#1#2{#1}
\def\@secondoftwo#1#2{#2}
\def\strip@prefix#1>{}
\newtoks\myscratchtoks
\long\def\poorman@detokenize#1#2{%
\myscratchtoks{#2}\edef#1{\the\myscratchtoks}%
\edef#1{\expandafter\strip@prefix\meaning#1}}%
\def\return@if@false{\expandafter\@secondoftwo\romannumeral}
\def\return@if@true{\expandafter\@firstoftwo\romannumeral}
\chardef\exp@end=0
%
\def\IfEmpty#1{%
\poorman@detokenize\@@tmpa{#1}%
\if\relax\@@tmpa\relax
\return@if@true
\else
\return@if@false
\fi\exp@end}
%
\def\IfContainedIn#1#2{%
\relax\iffalse{\fi
\def\if@contained@aux##1#2{}%
\expandafter\IfEmpty\expandafter{\if@contained@aux#1{}{}#2}%
{\return@if@false}{\return@if@true}%
\iffalse}\fi
\exp@end}
%
\def\StrIfContainedIn#1#2{%
\poorman@detokenize\@@tmpa{#1}%
\poorman@detokenize\@@tmpb{#2}%
\edef\@@tmpa{\noexpand\IfContainedIn
{\@@tmpa}{\@@tmpb}}\@@tmpa
{\return@if@true}{\return@if@false}%
\exp@end}
\catcode`\@=12
\StrIfContainedIn{hello}{el}{T}{F}
\StrIfContainedIn{hello}{le}{T}{F}
\bye
答案3
与我的其他答案不同的方法。这使用tokcycle
,而不是listofitems
。此处扩展的功能是能够深入查看组内容以查找所需字符串,而我的其他更简单的答案则无法做到这一点。同样,宏名称和组可以成为搜索字符串的一部分。
\input tokcycle
\def\findinstring#1#2#3#4{\begingroup%
\stripgroupingtrue
\runcount=0\relax%
\tokcycle{\nextctltok{##1}}
{\nextctltok{\opengroup}\processtoks{##1}\nextctltok{\closegroup}}
{\nextctltok{##1}}
{\nextctltok{\tcspace}}{#1}%
\edef\numlet{\the\runcount}%
\expandafter\def\expandafter\searchword\expandafter{\the\cytoks}%
\aftertokcycle{\expandafter\ifx\matchfound T#3\else#4\fi}%
\runcount=0\relax%
\def\matchfound{F}%
\tokcycle{\nextcmptok{##1}}
{\nextcmptok{\opengroup}\processtoks{##1}\nextcmptok{\closegroup}}
{\nextcmptok{##1}}
{\nextcmptok{\tcspace}}{#2}%
\endgroup}
\newcount\runcount
\catcode`@=11
\def\rotcytoks#1{\cytoks\expandafter\expandafter\expandafter{%
\expandafter\tc@gobble\the\cytoks#1}}
\catcode`@=12
\def\testmatch#1{\ifx#1\searchword\gdef\matchfound{T}\fi}%
\def\rotoradd#1#2{\runcount=\numexpr\runcount+1\relax%
\ifnum\the\runcount>\numlet\relax#1\else#2\fi\expandafter
\def\expandafter\tmp\expandafter{\the\cytoks}}
\def\nextcmptok#1{\rotoradd{\rotcytoks{#1}}{\addcytoks{#1}}\testmatch{\tmp}}
\def\nextctltok#1{\runcount=\numexpr\runcount+1\relax\addcytoks{#1}}
\findinstring{a\notmymac{b c}}{gf{vf{a\mymac{b c}g}gh}hn}{Found}{Not Found}
\findinstring{a\mymac{b c}}{gf{vf{a\mymac{b c}g}gh}hn}{Found}{Not Found}
\bye