我尝试\StrSubstitute
在循环中使用foreach
- 替换多个关键字,但无法累积所有结果。每次调用的结果\StrSubstitute
都会在循环中丢失。
我正在使用建议的方法捕获结果.示例代码如下:
\documentclass[11pt]{article}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{tikz}
\begin{document}
\def\KeyWords{one, two, three}
\def\MyText{This is one, followed by two later by three}
\expandarg
Original Text: \MyText\\
\foreach \keyword in \KeyWords
{
Replacing: \texttt{\keyword}
\StrSubstitute{\MyText}{\keyword}{\textbf{\keyword}}[\MyText]
Now MyText: \MyText \\ \\
}
Final: \MyText \
在上面的示例中,在每次迭代中,特定的单词一、二或三都会正确地变为粗体 - 但当它最终退出循环时,\MyText
最终结果与原始结果相同。
甚至\csgdef
不起作用(假设全局与局部定义是问题所在)。
尝试 \renewcommand{\MyText}{\StrSubstitute{\MyText}{\keyword}{\textbf{\keyword}}}
直接将替换结果分配给,\MyText
但它只是挂起,显示类似
[Loading MPS to PDF converter (version 2006.09.02).]
(我使用的是MikTeX
2.9,pdflatex
如果这很重要)
实现这一目标的正确机制是什么?
目标是用给定字符串中各自的替换词替换一个或多个以逗号分隔的提供的关键字。
答案1
问题是每次循环都是在一个组内进行的。因此,替换后\foreach
您必须全局保存;然而,一个简单的\MyText
\documentclass[11pt]{article}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{tikz}
\begin{document}
\def\KeyWords{one, two, three}
\def\MyText{This is one, followed by two later by three}
\expandarg
Original Text: \MyText\\
\foreach \keyword in \KeyWords
{
Replacing: \texttt{\keyword}
\StrSubstitute{\MyText}{\keyword}{\textbf{\keyword}}[\temp]%
\global\let\MyText\temp
Now MyText: \MyText \\
}
Final: \MyText
\end{document}
将不起作用,因为关键字被替换\textbf{\keyword}
,因此\keyword
不会扩展。
您必须扩展\keyword
替换字符串;例如使用
\documentclass[11pt]{article}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{tikz}
\begin{document}
\def\KeyWords{one, two, three}
\def\MyText{This is one, followed by two later by three}
\expandarg
Original Text: \MyText
\foreach \keyword in \KeyWords
{
Replacing: \texttt{\keyword}
\begingroup\edef\x{\endgroup
\unexpanded{\StrSubstitute{\MyText}{\keyword}}
{\noexpand\textbf{\keyword}}}\x[\temp]
\global\let\MyText\temp
Now MyText: \MyText \\
}
Final: \MyText
\end{document}
我建议采用不同的方法l3regex
:
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\setkeywords}{m}
{
\gopa_set_keywords:n { #1 }
}
\NewDocumentCommand{\changekeywords}{ O{textbf} m}
{
\gopa_change_keywords:nn { #1 } { #2 }
}
\cs_new_protected:Npn \gopa_set_keywords:n #1
{
\seq_set_split:Nnn \l_gopa_keywords_seq { , } { #1 }
\tl_set:Nx \l_gopa_keywords_tl { \seq_use:Nn \l_gopa_keywords_seq { | } }
\tl_put_left:Nn \l_gopa_keywords_tl { \b( }
\tl_put_right:Nn \l_gopa_keywords_tl { ) }
\regex_gset:NV \g_gopa_keywords_regex \l_gopa_keywords_tl
}
\cs_new_protected:Npn \gopa_change_keywords:nn #1 #2
{
\tl_set:Nn \l_gopa_sentence_tl { #2 }
\regex_replace_all:NnN \g_gopa_keywords_regex { \c{#1}\cB\{\1\cE\} } \l_gopa_sentence_tl
\tl_use:N \l_gopa_sentence_tl
}
\tl_new:N \l_gopa_keywords_tl
\tl_new:N \l_gopa_sentence_tl
\seq_new:N \l_gopa_keywords_seq
\regex_new:N \g_gopa_keywords_regex
\cs_generate_variant:Nn \regex_gset:Nn { NV }
\ExplSyntaxOff
\setkeywords{one, two, three}
\begin{document}
\changekeywords{This is one, followed by two later by three}
\changekeywords[textit]{This is one, followed by two later by three}
\end{document}
该\setkeywords
命令定义要更改的关键字;使用 \changekeywords 您可以指定文本,并且可以指定要使用的格式(仅控制序列名称,而不是命令)。
它是如何工作的?从关键字列表中,我们准备一个正则表达式,格式为
\b ( one | two | three )
已构建。匹配项将替换为,\textbf{\1}
其中\1
表示匹配的字符串。
答案2
这是另一种方法,使用stringstrings
。缺点:它是一个缓慢的包。
\documentclass[12pt]{article}
\usepackage{stringstrings}
\newcounter{index}
\newcommand\emboldenkeywords[2]{%
\getargs{#1}%
\setcounter{index}{0}%
\edef\thestring{#2}%
\encodetoken[1]{\bfseries}
\encodetoken[2]{\mdseries}
\whiledo{\value{index} < \narg}{%
\stepcounter{index}%
\edef\nextkeyword{\csname arg\roman{index}\endcsname}%
\convertword[e]{\thestring}{\nextkeyword}{\bfseries\nextkeyword\mdseries}%
}%
\retokenize{\thestring}%
\thestring%
\decodetoken[1]{\bfseries}
\decodetoken[2]{\mdseries}
}
\begin{document}
\emboldenkeywords{one two three}{This is one, followed by two later by three}
\end{document}