我一直在尝试制作一个命令,允许我自动重新输入给定字符串中的任何 V̇,因为我使用的字体将其输入为 .V,这并不理想。XeLaTeX
我使用这个源代码编译了
\documentclass{article}
\usepackage{xstring}
\usepackage{stackengine}
\newcommand{\Vh}{\stackon[1pt]{V}{.}}
\newcommand{\dothing}[1]{\StrSubstitute{#1}{V̇}{\Vh}}
\begin{document}
\dothing{V̇aglæja}
\end{document}
并收到以下错误:
Use of \\stackon doesn’t match its definition.
\kernel@ifnextchar ...d@d =#1\def\reserced@a{#2}
\def\reserved@b{#3}\futu...
l.8\dothing{V̇aglæja}
Argument of \\stackon has an extra }.
<inserted text>
\par
l.8\dothing{V̇aglæja}
Runaway argument?
! Paragraph ended before \\stackon was complete.
<to be read again>
\par
l.8\dothing{V̇aglæja}
Undefined Control Sequence.
\xs_StrSubstitute__..._arg_iv{#4}\edef\xs_call
{\noexpand\xs_testopt {\n...
l.8\dothing{V̇aglæja}
Undefined Control Sequence.
\xs_StrSubstitute__...d\xs_arg_iv}}{}}\xs_call
l.8\dothing{V̇aglæja}
Missing \endcsname inserted.
<to be read again>
\protect
l.8\dothing{V̇aglæja}
Undefined Control Sequence.
\GenericError ...
#4 \errhelp \@err@
l.9\end{document}
Undefined Control Sequence.
\GenericError ...
\let \@err@ ...
l.9\end{document}
Undefined Control Sequence.
\GenericError ...
\@empty \def\MessageBreak…
l.9\end{document}
Undefined Control Sequence.
\GenericError ...
\endgroup
l.9\end{document}
Missing \endcsname inserted.
<to be read again>
\let
l.8\dothing{V̇aglæja}
Incomplete \ifx; all text was ignored after line 9.
<inserted text>
\fi
<*> main.tex
stackengine
这些是什么意思?为什么会发生这种情况?这与结合和有关吗xstring
?谢谢!
答案1
您必须使用\expandarg
才能\StrSubstitute
展开\Vdot
。我还添加了\kern-1.5pt
来调整 V 和 a 之间的空间。(我不确定这是否是一个好的解决方案,或者它是否通常有效,即使它在这种情况下有效。)
\documentclass{article}
\usepackage{xstring}
\usepackage{stackengine}
\newcommand{\Vdot}{\stackon[1pt]{V}{.}\kern-1.5pt}
\newcommand{\dothing}[1]{\expandarg\StrSubstitute{#1}{V̇}{\Vdot}}
\begin{document}
\dothing{V̇aglæja}
\end{document}
答案2
使用具有良好锚点的字体来组合字符。
或者,使用更好的方法进行替换。
\documentclass{article}
\usepackage{fontspec}
\newfontfamily{\libertinus}{Libertinus Serif}
\ExplSyntaxOn
\NewDocumentCommand{\dothing}{m}
{
\tl_set:Nn \l_dothing_text_tl { #1 }
\regex_replace_all:nnN { V\x{0307} } { \c{dottedV} } \l_dothing_text_tl
\tl_use:N \l_dothing_text_tl
}
\tl_new:N \l_dothing_text_tl
\ExplSyntaxOff
\NewDocumentCommand{\dottedV}{}{%
\leavevmode
\vbox{%
\offinterlineskip
\ialign{%
\hfil##\hfil\cr
\.{}\cr
\noalign{\kern-1.1ex}%
V\cr
}%
}%
}
\begin{document}
V̇aglæja
\dothing{V̇aglæja}
\libertinus
V̇aglæja
\end{document}
您可以\dottedV
按照自己喜欢的方式定义,也可以使用stackengine
自己喜欢的方式定义。
我们还可以通过扩展代码来重新插入正确的字距。
\documentclass{article}
\usepackage{fontspec}
\newfontfamily{\libertinus}{Libertinus Serif}
\ExplSyntaxOn
\NewDocumentCommand{\dothing}{m}
{
\tl_set:Nn \l_dothing_text_tl { #1 }
\regex_replace_all:nnN { V\x{0307} } { \c{dottedV} } \l_dothing_text_tl
\tl_use:N \l_dothing_text_tl
}
\tl_new:N \l_dothing_text_tl
\NewDocumentCommand{\checkkern}{m}
{
\peek_catcode:NT { #1 } { \addkern{#1} }
}
\ExplSyntaxOff
\NewDocumentCommand{\dottedV}{}{%
\leavevmode
\vbox{%
\offinterlineskip
\ialign{%
\hfil##\hfil\cr
\.{}\cr
\noalign{\kern-1.1ex}%
V\cr
}%
}%
\checkkern{V}%
}
\NewDocumentCommand{\addkern}{mm}{%
\sbox0{#1#2}\sbox2{\hbox{#1}\hbox{#2}}%
\kern\dimexpr\wd0-\wd2\relax #2%
}
\begin{document}
V̇aglæja
\dothing{V̇aglæja}
Vaglæja
\libertinus
V̇aglæja
Vaglæja
\end{document}
请注意,Libertinus 示例中没有考虑字距调整。如果在决定字距调整时忽略组合字符,这将是 XeTeX 的一个很好的功能。
答案3
这里我设计了一个 tokcycle
名为的环境\dothing
,它可以扩展到多个段落,甚至扩展到整个文档。只需以 终止即可\enddothing
。
已编辑以删除\makeatletter
代码,该代码现已合并到 中tokcycle[2021-05-27]
。此外,还消除了 的一个先前故障模式\Vdotcheck
以及其他潜在故障模式(包括 之后的空格V
和/或 之后的组V
)。
\documentclass{article}
\usepackage{tokcycle}[2021-05-27]
\usepackage{stackengine}
\newcommand{\Vh}{\stackon[1pt]{V}{.}}
\def\zz#1#2{#2}
\edef\thedot{\zz V̇}
\newcommand\Vdotcheck{\tcpopliteral\z
\ifx\thedot\z\addcytoks{\Vh}\else
\addcytoks{V}\tcpush\z\fi}
\tokcycleenvironment\dothing
{\ifx V##1\Vdotcheck\else\addcytoks{##1}\fi}%
{\processtoks{##1}}
{\addcytoks{##1}}
{\addcytoks{##1}}
\begin{document}
\dothing
V̇aglæja
V\today % MACRO AFTER V
V{\itshape a}bc% GROUP AFTER V
V bc% SPACE AFTER V
xV̇x VV̇% V̇ AFTER V
\enddothing
\end{document}