我想定义一个命令,它接受一个名称并从中创建一个可读的字符串,该字符串可以用作文件名。例如
John Doe
-> doe-john
。
但是,我想避免使用特殊字符,即用非 ASCII 字符替换其 ASCII 等效字符。也就是说,我需要一个宏来删除重音符号并替换一些特殊字母,例如
æüßéñ
-> aeuessen
。
有没有办法在 LaTeX 中以合理的努力做到这一点?
答案1
如果您使用的是inputenc
(而不是 XeLaTeX/LuaLaTeX),您可以利用将inputenc
扩展字符转换为重音命令这一事实。例如,ü
扩展为\IeC{\"u}
。因此,您可以暂时重新定义重音命令以将其删除。
例子:
\documentclass{article}
\usepackage[utf8]{inputenc}
\makeatletter
\newcommand{\stripaccents}[2]{%
\begingroup
% strip accents:
\let\add@accent\@secondoftwo
% provide replacement strings:
\def\AE{AE}%
\def\ae{ae}%
\def\OE{OE}%
\def\oe{oe}%
\def\AA{AA}%
\def\aa{aa}%
\def\L{L}%
\def\l{l}%
\def\O{O}%
\def\o{o}%
\def\SS{SS}%
\def\ss{ss}%
\def\th{th}%
\def\TH{TH}%
\def\dh{dh}%
\def\DH{DH}%
\xdef#1{#2}%
\endgroup
}
\makeatother
\begin{document}
\stripaccents\tmp{æüßéñ}
\show\tmp
\end{document}
由此可见:
> \tmp=macro:
->aeussen.
如果您的输入中可能出现任何其他命令,则需要添加它们,\stripaccents
以便它们扩展为合理的内容。
对于变音符号,您可以暂时重新定义,\"
以便它附加e
到其参数:
\newcommand{\stripaccents}[2]{%
\begingroup
\def\"##1{##1e}% umlaut
\let\add@accent\@secondoftwo
\def\AE{AE}%
\def\ae{ae}%
\def\OE{OE}%
\def\oe{oe}%
\def\AA{AA}%
\def\aa{aa}%
\def\L{L}%
\def\l{l}%
\def\O{O}%
\def\o{o}%
\def\SS{SS}%
\def\ss{ss}%
\def\th{th}%
\def\TH{TH}%
\def\dh{dh}%
\def\DH{DH}%
\xdef#1{#2}%
\endgroup
}
现在显示:
> \tmp=macro:
->aeuessen.
使用 T1 编码您还需要:
\let\@text@composite@x\@secondoftwo
在 的定义中\stripaccents
,正如您在评论中提到的那样。
答案2
您必须根据给出的示例自行填充列表。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \g_schtandard_search_replace_seq
\seq_gput_right:Nn \g_schtandard_search_replace_seq { {æ}{ae} }
\seq_gput_right:Nn \g_schtandard_search_replace_seq { {ä}{ae} }
\seq_gput_right:Nn \g_schtandard_search_replace_seq { {ö}{oe} }
\seq_gput_right:Nn \g_schtandard_search_replace_seq { {ü}{ue} }
\seq_gput_right:Nn \g_schtandard_search_replace_seq { {ß}{ss} }
\seq_gput_right:Nn \g_schtandard_search_replace_seq { {ñ}{n} }
\seq_gput_right:Nn \g_schtandard_search_replace_seq { {é}{e} }
\tl_new:N \l_schtandard_input_tl
\NewDocumentCommand{\makestring}{om}
{
\tl_set:Nn \l_schtandard_input_tl { #2 }
\seq_map_inline:Nn \g_schtandard_search_replace_seq
{
\regex_replace_all:nnN ##1 \l_schtandard_input_tl
}
\IfNoValueTF{#1}
{
\tl_use:N \l_schtandard_input_tl
}
{
\tl_set_eq:NN #1 \l_schtandard_input_tl
}
}
\ExplSyntaxOff
\begin{document}
\makestring{æüßéñ}
\makestring[\foo]{æüßéñ}\texttt{\meaning\foo}
\end{document}
答案3
如果你只需要文件名,但不需要它们是“人类可读的”,那么你可以利用\pdfstringdef
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[unicode]{hyperref}
\makeatletter
\begingroup
\catcode`| 0 \catcode`\\ 12
|gdef|makestring@i\#1#2#3#4%
{#1#2#3|if|relax#4|expandafter|@gobbletwo|fi|makestring@i#4}
|endgroup
\newcommand*{\makestring}[2]{%
\pdfstringdef\makestring@{#2}%
\edef#1{\expandafter\makestring@i\makestring@\relax}%
}
\makeatother
\begin{document}
\makestring{\foo}{æüßéñ}
\texttt{\meaning\foo}
\end{document}
此主题的一个变体效率更高,它显示 utf8 字节。如果需要,可以生成十六进制。(实际上,utf8.def
这里可能可以使用宏)
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\makeatletter
\newcommand*\MakeString[2]{%
\begingroup
\def\UTFviii@two@octets##1##2{\the\numexpr`##1\relax\the\numexpr`##2}%
\def\UTFviii@three@octets##1##2##3{\the\numexpr`##1\relax\the\numexpr`##2\relax\the\numexpr`##3\relax}%
\def\UTFviii@four@octets##1##2##3##4{\the\numexpr`##1\relax\the\numexpr`##2\relax\the\numexpr`##3\relax\the\numexpr`##4\relax}%
\xdef#1{#2}%
\endgroup
}
\makeatother
\begin{document}
\MakeString{\foo}{æüßéñ}
\texttt{\meaning\foo}
\show\foo
\end{document}
生成:
> \foo=macro:
->195166195188195159195169195177.
l.23 \show\foo
我应该改进,以便每个字节产生一个三位数的小数,这里前导零被去掉!
好的,这里没有剥离并且每个字节有 2 个十六进制数字。
编辑删除了额外包的使用。定义的\Byte@tohex
宏可能已由utf8-inputenc
内部提供,未经检查。
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\makeatletter
% I have not checked but maybe utf8-inputenc provides already
% similar macro (not even using e-TeX)
\def\Byte@tohex #1%
{\expandafter
\Byte@tohex@\the\numexpr(`#1+8)/16-1\expandafter
.\the\numexpr`#1.}%
\def\Byte@tohex@ #1.#2.%
{\Byte@onehex #1.%
\expandafter\Byte@onehex\the\numexpr #2-16*#1.%
}
\def\Byte@onehex #1.%
{\ifcase #1
0\or1\or2\or3\or4\or5\or6\or7\or8\or9%
\or A\or B\or C\or D\or E\or F%
\fi
}%
\newcommand*\MakeString[2]{%
\begingroup
\def\UTFviii@two@octets##1##2{\Byte@tohex{##1}\Byte@tohex{##2}}%
\def\UTFviii@three@octets##1##2##3{\Byte@tohex{##1}\Byte@tohex{##2}\Byte@tohex{##3}}%
\def\UTFviii@four@octets##1##2##3##4{\Byte@tohex{##1}\Byte@tohex{##2}\Byte@tohex{##3}\Byte@tohex{##4}}%
\xdef#1{#2}%
\endgroup
}
\makeatother
\begin{document}
\MakeString{\foo}{æüßéñ}
\texttt{\meaning\foo}
\show\foo
\end{document}
在日志中产生
> \foo=macro:
->C3A6C3BCC39FC3A9C3B1.
l.27 \show\foo