我正在尝试使用 向辅助文件输出一些信息\write
,除其他外,我的作者姓名通常包含重音字母。如果我明确使用字符串,重音字母将扩展为 TeX 命令,但我可以使用 来解决这个问题\unexpanded
。但是,如果字符串包含在变量中,并且我使用,我会得到变量的名称而不是其内容。如果变量是命令参数,例如,\unexpanded
则该命令可以正常工作。\unexpanded
#1
我对扩展的理解不够清晰,无法解决这个问题,所以任何帮助我都感激不尽。我想要做的就是将一个包含带重音字母的字符串的变量的内容写入文本文件。
这是一个简单的例子:
\documentclass{article}
\usepackage[utf8]{inputenc}
\newwrite\file
\immediate\openout\file=\jobname_extra.txt
\AtEndDocument{\closeout\file}
\begin{document}
\immediate\write\file{Test 1} % works fine
\immediate\write\file{José} % expands into TeX code
\immediate\write\file{\unexpanded{José}} % works fine
\def\mystring{José}
\immediate\write\file{\mystring} % expands into TeX code
\immediate\write\file{\unexpanded{\mystring}} % outputs \mystring literally
\newcommand{\writeaccented}[1]{
\immediate\write\file{\unexpanded{#1}}
}
\writeaccented{José} % works fine
\end{document}
编辑:我收到了两个答案,要么使用 要么使用\expandafter\unexpanded\expandafter{\mystring}
。\detokenize\expandafter{\mystring}
这些在上面的最小示例中运行良好,但在实际示例中却不行,这让我认为我的情况中的扩展发生得更早。以下是更接近我的真实情况的新最小示例:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{xstring}
\newwrite\file
\immediate\openout\file=\jobname_extra.txt
\AtEndDocument{\closeout\file}
\begin{document}
\def\listofauthors{José Saramago, Luigi Pirandello and Władysław Reymont}
\makeatletter
\StrSubstitute[0]{\listofauthors}{, }{,}[\@cpauthors]
\StrSubstitute[0]{\@cpauthors}{ and }{,}[\@cpauthors]
\@for \@cpauthor:=\@cpauthors\do{%
\immediate\write\file{<author>\expandafter\unexpanded\expandafter{\@cpauthor}</author>}
}
\makeatother
\end{document}
编辑 2:添加\usepackage[T1]{fontenc}
可防止扩展到 TeX 命令,但会以 ISO-8859 编码而不是 unicode 输出重音字母。我尝试了有和没有建议的解决方案。
编辑 3:对我有用的解决方案是https://tex.stackexchange.com/a/390119/36823。 谢谢你!
答案1
您可以使用\detokenize
:
\documentclass{article}
\usepackage[utf8]{inputenc}
\newwrite\file
\immediate\openout\file=\jobname_extra.txt
\AtEndDocument{\closeout\file}
\begin{document}
\def\mystring{José}
\immediate\write\file{\detokenize\expandafter{\mystring}} % outputs \mystring literally
\end{document}
该文件的内容_extra
是
José
十六进制转储:
0000000 4a 6f 73 c3 a9 0a
0000006
的 UTF-8 表示é
确实是C3 A9
。
针对更复杂情况的不同方法:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{xparse}
\ExplSyntaxOn
\iow_new:N \g_giampiero_output_stream
\tl_new:N \l__giampiero_write_temp_tl
\AtBeginDocument
{
\iow_open:Nn \g_giampiero_output_stream { \c_sys_jobname_str _extra.txt }
}
\AtEndDocument
{
\iow_close:N \g_giampiero_output_stream
}
\NewDocumentCommand{\writeauthors}{sm}
{% *-version for doing a variable
\IfBooleanTF{#1}
{
\giampiero_writeauthors:V #2
}
{
\giampiero_writeauthors:n { #2 }
}
}
\cs_new_protected:Nn \giampiero_writeauthors:n
{
\tl_set:Nn \l__giampiero_write_temp_tl { #1 }
\tl_replace_all:Nnn \l__giampiero_write_temp_tl { ~and~ } { , }
\seq_set_split:NnV \l__giampiero_write_temp_seq { , } \l__giampiero_write_temp_tl
\seq_map_inline:Nn \l__giampiero_write_temp_seq
{
\giampiero_write_generic:nn { author } { ##1 }
}
}
% This can be used for other similar write operations
\cs_new_protected:Nn \giampiero_write_generic:nn
{
\iow_now:Nn \g_giampiero_output_stream { <#1>#2</#1> }
}
\cs_generate_variant:Nn \seq_set_split:Nnn {NnV}
\cs_generate_variant:Nn \giampiero_writeauthors:n { V }
\ExplSyntaxOff
\newcommand\listofauthors{José Saramago, Luigi Pirandello and Władysław Reymont}
\begin{document}
\writeauthors{José Saramago, Luigi Pirandello and Władysław Reymont}
\writeauthors*{\listofauthors}
\end{document}
以下是生成的文件的内容:
<author>José Saramago</author>
<author>Luigi Pirandello</author>
<author>Władysław Reymont</author>
<author>José Saramago</author>
<author>Luigi Pirandello</author>
<author>Władysław Reymont</author>
答案2
扩展是 TeX 中的一个怪兽 ;-)
\immediate\write\file{\expandafter\unexpanded\expandafter{\mystring}} %
\mystring
将首先扩展其内容,\unexpanded
然后才能再次“保护”它。
\documentclass{article}
\usepackage[utf8]{inputenc}
\newwrite\file
\immediate\openout\file=\jobname_extra.txt
\AtEndDocument{\closeout\file}
\begin{document}
\immediate\write\file{Test 1} % works fine
\immediate\write\file{José} % expands into TeX code
\immediate\write\file{\unexpanded{José}} % works fine
\def\mystring{José}
\immediate\write\file{\mystring} % expands into TeX code
\immediate\write\file{\expandafter\unexpanded\expandafter{\mystring}} % outputs \mystring literally
\newcommand{\writeaccented}[1]{
\immediate\write\file{\unexpanded{#1}}
}
\writeaccented{José} % works fine
\end{document}
输出:(%%%%由我注释)
Test 1
Jos\unhbox \voidb@x \bgroup \let \unhbox \voidb@x \setbox \@tempboxa \hbox {e\global \mathchardef \accent@spacefactor \spacefactor }\accent 19 e\egroup \spacefactor \accent@spacefactor
José
Jos\unhbox \voidb@x \bgroup \let \unhbox \voidb@x \setbox \@tempboxa \hbox {e\global \mathchardef \accent@spacefactor \spacefactor }\accent 19 e\egroup \spacefactor \accent@spacefactor
José%%%%% This one is from \expandafter\unexpanded\expandafter{\mystring}
José
答案3
回答示例xstring
包xstring
有几种扩展模式,请参阅文档。
在这种情况下,\listofauthors
应包含示例中给出的纯作者姓名。然后,模式\expandarg
仅扩展第一个标记 macro \listofauthors
,但不进行进一步扩展。
\expandarg
该示例通过组限制了的效果。它使用\detokenize
并删除了不必要的\expandafter
。
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{xstring}
\newwrite\file
\immediate\openout\file=\jobname_extra.txt
\AtEndDocument{\closeout\file}
\begin{document}
\def\listofauthors{José Saramago, Luigi Pirandello and Władysław Reymont}
\makeatletter
\begingroup
\expandarg
\StrSubstitute[0]{\listofauthors}{, }{,}[\@cpauthors]
\StrSubstitute[0]{\@cpauthors}{ and }{,}[\@cpauthors]
\@for \@cpauthor:=\@cpauthors\do{%
\immediate\write\file{<author>\detokenize\expandafter{\@cpauthor}</author>}
}
\endgroup
\makeatother
\end{document}
文件\jobname_extra.txt
:
<author>José Saramago</author>
<author>Luigi Pirandello</author>
<author>Władysław Reymont</author>