我正在尝试替换给定字符串中的某些字符。要替换的字符由其 ASCII 码给出。例如,在 中abc
,我想用其他字符(比如说点 ( ))替换字符97
(即a
,但我还不知道).
。
现在,a
在文档中打印时,\char97
和\char\thenumber
对我来说都一样,但在字符串中替换相应的参数a
仅适用于第一个。为什么会这样,我该如何解决?这是我的 MWE(与原始问题没有变化):
\documentclass{book}
\usepackage{xstring}
\newcounter{number}
\setcounter{number}{97}
\newcommand{\replace}[1]{\StrSubstitute{#1}{a}{.}}
\begin{document}
a
\char97
\char\thenumber
\replace{a}
\expandafter\replace{\char97}
\expandafter\expandafter\expandafter\replace{\char\thenumber}
\end{document}
答案1
有一个标准\lowercase
技巧,即使用给定的 ASCII 代码创建一个标记。例如,您需要用abcabcac
double替换字符串中的所有 ASCII 97 个字符?
。然后您可以尝试:
\bgroup\lccode`X=97 \lowercase{\egroup \StrSubstitute{abcabcabc}{X}{??}}
output: ??bc??bc??bc
此代码使用给定的 ASCII 代码(而不是字母)创建标记X
,然后\StrSubstitute
执行宏。
当然,你处理的字符串不能包含X
字母本身。如果这是一个问题,那么你可以创建以下\replace
宏:
\def\replace#1{\bgroup \lccode`X=#1 \lowercase{\egroup \replaceA{X}}{abcabcabcXuv}}
\def\replaceA#1#2{\StrSubstitute{#2}{#1}{??}}
\replace{97}
output: ??bc??bc??bcXuv
\replace{98}
output: a??ca??ca??cXuv
答案2
TeX\char
基元不可扩展。这意味着在示例中尝试扩展
\expandafter\replace\expandafter{\char97}
不执行任何操作,相当于
\replace{\char97}
由于显而易见的原因,它无法匹配文字a
。因此,需要一些可扩展的方法将数字转换为字符。经典 TeX 为我们提供了\ifcase
原语,它以一般形式使用
\ifcase<number> %
<case 0>\or
<case 1>\or
<case 2>\or
...
<case n>\else
<no match>
\fi
因此,通过适当的设置,可以进行逐个转换。LaTeX\@alph
和 就采用了这种方法\@Alph
,它们分别从 1 开始索引小写字母/大写字母:
\@alph{1}% => a
显然,这里需要进行一些数学运算才能正确获得偏移量。这种方法可扩展,但对于长字符列表来说显然很繁琐。
可以设置一个可扩展的“选择性”案例陈述:例如有一个预先内置的expl3
\int_case:nnF { <number> }
{
{ 97 } { a }
{ 101 } { e }
{ 105 } { i }
{ 111 } { o }
{ 117 } { u }
}
{ No~match }
对于连续整数范围的短列表,与原语相比,性能会受到影响,但输入格式和清晰度更好,特别是对于长列表。(我认为除了这个之外,还有其他相同概念的实现expl3
。)
任何逐案处理方法的问题在于,如果你将目光投向 ASCII 以外的整个 UTF-8 范围。如果使用 LuaTeX,那么是一个可扩展的原语,可以完成这项工作
\Uchar97 % => a
如果您能确定正在使用的引擎,这显然是最简单的解决方案。
答案3
我想要实现的是使用\@Alph
和实现的\@alph
,因为我的输入 ASCII 代码在 az、AZ 范围内。\@Alph
等似乎扩展为“真实”字母。正如其他许多人指出的那样,\char
是不可扩展的。我希望这有时可以帮助别人。