由于我对 还很陌生expl3
,我用它编写的第一个包crefthe
有很多不正确的语法。感谢 Joseph Wright 的回答和@egreg的回答,我设法修正了一些,但肯定还有更多。当前版本列在最后。
以下是 @egreg 指出的两个我无法修复的问题:
更改
\exp_args:Nx \str_case:nn
为会\str_case:Vn
破坏功能(介词消失),这可能是由于\str_case_e:nn { \languagename }
内部造成的\l__crefthe_prep_mode_tl
,但我不确定。更改
\text_lowercase:n
为\str_foldcase:n
也会破坏冠词缩写功能,即使我将其扩展为使用\str_foldcase:x
冠词缩写,仍然无法正常工作。(顺便问一下,我可以假设\text_lowercase:n
shall 始终扩展其参数吗,或者最好创建一个:x
变体并使用它来确定?)
expl3
如果您发现任何不正确的使用方法,或者您有更好的实现方法,请随时告诉我。提前谢谢您!
以下是测试文档:
\documentclass{article}
\usepackage{amsthm}
\usepackage{hyperref}
\usepackage[nameinlink,french]{crefthe}
\usepackage[french]{babel}
\newtheorem{thm}{Théorème}
\newtheorem{thmn}{Théorème facile}
\crefthename{thm}[le]{théorème}[les]{théorèmes}
\crefthename{thmn}[le]{théorème facile}[les]{théorèmes faciles}
\Crefthename{thm}[Le]{théorème}[Les]{théorèmes}
\Crefthename{thmn}[Le]{théorème facile}[Les]{théorèmes faciles}
\begin{document}
\begin{thm}\label{thm1}
some text.
\end{thm}
\begin{thm}\label{thm2}
more text.
\end{thm}
\begin{thmn}\label{thmn1}
more other text.
\end{thmn}
- Single one -
\crefthe[\`A]{thm1}, \crefthe[\`a]{thm1}
\crefthe[À]{thm1}, \crefthe[à]{thm1}
\Crefthe[à]{thm1}, \crefthe[à]{thm1}
\Crefthe[À]{thm1}, \crefthe[à]{thm1}
\crefthe[de]{thm1}
\Crefthe[de]{thm1}
- Multiple ones -
\crefthe[À]{thm1,thmn1}
\Crefthe[À]{thm1,thmn1}
\crefthe[À]{thm1,thm2}
\Crefthe[À]{thm1,thm2}
\Crefthe[De]{thm1,thm2,thmn1}
\Crefthe{thm1,thm2,thmn1}
\crefthe{thm1,thm2}
\end{document}
正确的结果应该是:
当前版本 (2022-02-09) crefthe
:
\NeedsTeXFormat{LaTeX2e}[2020-10-01]
\RequirePackage{l3keys2e}
\ProvidesExplPackage
{crefthe}
{2022/02/09} {}
{Cross referencing with proper definite articles}
\keys_define:nn { crefthe }
{
, overwrite .bool_set:N = \l__crefthe_overwrite_bool
, overwrite .initial:n = { false }
, unknown .code:n =
{
\PassOptionsToPackage { \CurrentOption } { cleveref }
}
}
\ProcessKeysOptions { crefthe }
\RequirePackage { cleveref }
\cs_set_eq:cc { crefthe_cref_original:w } { cref }
\cs_set_eq:cc { crefthe_Cref_original:w } { Cref }
\cs_set_eq:cc { crefthe_crefname_original:w } { crefname }
\cs_set_eq:cc { crefthe_Crefname_original:w } { Crefname }
\bool_if:NT \l__crefthe_overwrite_bool
{
\hook_gput_next_code:nn { package/crefthe/after }
{
% \RenewCommandCopy \cref \crefthe
% \RenewCommandCopy \Cref \Crefthe
% \RenewCommandCopy \crefname \crefthename
% \RenewCommandCopy \Crefname \Crefthename
\cs_set_eq:cc { cref } { crefthe }
\cs_set_eq:cc { Cref } { Crefthe }
\cs_set_eq:cc { crefname } { crefthename }
\cs_set_eq:cc { Crefname } { Crefthename }
}
}
\tl_new:N \g__crefthe_prep_once_tl
\tl_new:N \g__crefthe_prep_each_tl
\tl_new:N \l__crefthe_prep_mode_tl
\bool_new:N \g__crefthe_uppercase_bool
\NewDocumentCommand \crefthe { s t- t+ O{} m }
{
\bool_set_false:N \g__crefthe_uppercase_bool
\bool_if:nTF { #2 }
{
\tl_gset:Nn \g__crefthe_prep_once_tl { #4 }
}
{
\bool_if:nTF { #3 }
{
\tl_gset:Nn \g__crefthe_prep_each_tl { #4 }
}
{
\exp_args:Nx \str_case:nn \l__crefthe_prep_mode_tl
{
{ - } { \tl_gset:Nn \g__crefthe_prep_once_tl { #4 } }
{ + } { \tl_gset:Nn \g__crefthe_prep_each_tl { #4 } }
}
}
}
\bool_if:nTF { #1 } { \crefthe_cref_original:w * { #5 } } { \crefthe_cref_original:w { #5 } }
\tl_gset:Nn \g__crefthe_prep_each_tl {}
}
\NewDocumentCommand \Crefthe { s t- t+ O{} m }
{
\bool_set_true:N \g__crefthe_uppercase_bool
\bool_if:nTF { #2 }
{
\tl_gset:Nn \g__crefthe_prep_once_tl { #4 }
}
{
\bool_if:nTF { #3 }
{
\tl_gset:Nn \g__crefthe_prep_each_tl { #4 }
}
{
\exp_args:Nx \str_case:nn \l__crefthe_prep_mode_tl
{
{ - } { \tl_gset:Nn \g__crefthe_prep_once_tl { #4 } }
{ + } { \tl_gset:Nn \g__crefthe_prep_each_tl { #4 } }
}
}
}
\bool_if:nTF { #1 } { \crefthe_Cref_original:w * { #5 } } { \crefthe_Cref_original:w { #5 } }
\tl_gset:Nn \g__crefthe_prep_each_tl {}
}
\NewDocumentCommand \crefthename { m O{} m O{} m }
{
\tl_if_blank:eTF { #2 }
{
\crefthe_crefname_original:w { #1 } { #3 } { #5 }
\cs_set:cn { cref_#1_format:nnn } { ##2 #3 ~ ##1 ##3 }
\cs_set:cn { cref_#1_format_first:nnn } { ##2 #5 ~ ##1 ##3 }
}
{
\crefthe_crefname_original:w { #1 } { \crefthemark{ #2 } #3 } { \crefthemark{ #4 } #5 }
\cs_set:cn { cref_#1_format:nnn } { \crefthemark { #2 } ##2 #3 ~ ##1 ##3 }
\cs_set:cn { cref_#1_format_first:nnn } { \crefthemark { #4 } ##2 #5 ~ ##1 ##3 }
}
\hook_gput_code:nnn { begindocument } { crefthe }
{
\cs_set_eq:cc { cref@ #1 @format } { cref_#1_format:nnn }
\cs_set_eq:cc { cref@ #1 @format@first } { cref_#1_format_first:nnn }
}
}
\NewDocumentCommand \Crefthename { m O{} m O{} m }
{
\tl_if_blank:eTF { #2 }
{
\crefthe_Crefname_original:w { #1 } { #3 } { #5 }
\cs_set:cn { Cref_#1_format:nnn } { ##2 #3 ~ ##1 ##3 }
\cs_set:cn { Cref_#1_format_first:nnn } { ##2 #5 ~ ##1 ##3 }
}
{
\crefthe_Crefname_original:w { #1 } { \crefthemark{ #2 } #3 }{ \crefthemark{ #4 } #5 }
\cs_set:cn { Cref_#1_format:nnn } { \crefthemark { #2 } ##2 #3 ~ ##1 ##3 }
\cs_set:cn { Cref_#1_format_first:nnn } { \crefthemark { #4 } ##2 #5 ~ ##1 ##3 }
}
\hook_gput_code:nnn { begindocument } { crefthe }
{
\cs_set_eq:cc { Cref@ #1 @format } { Cref_#1_format:nnn }
\cs_set_eq:cc { Cref@ #1 @format@first } { Cref_#1_format_first:nnn }
}
}
\NewDocumentCommand \crefthemark { m }
{
\crefthe_contraction:nn { \g__crefthe_prep_each_tl }
{
\crefthe_contraction:nn { \g__crefthe_prep_once_tl } { #1 }
}
\tl_gset:Nn \g__crefthe_prep_once_tl {}
\tl_gset:Nx \g__crefthe_prep_each_tl { \text_lowercase:n \g__crefthe_prep_each_tl }
\str_if_eq:eeF { \str_tail:n { #1 } } { ' } { ~ }
\bool_set_false:N \g__crefthe_uppercase_bool
}
\prg_generate_conditional_variant:Nnn \str_case_e:nn { nv } { p, T, F, TF }
\tl_set:Nn \l__crefthe_prep_mode_tl {
\str_case_e:nn { \languagename }
{
{french} { + }
{italian} { + }
{spanish} { - }
{portuguese} { + }
{brazilian} { + }
}
}
\cs_new:Npn \crefthe_contraction:nn #1#2
{
\tl_if_blank:eTF { #1 }
{ #2 }
{
\tl_if_exist:cTF { g_crefthe_contraction_rule_ \languagename _tl }
{
\bool_if:NTF \g__crefthe_uppercase_bool
{
\str_case_e:nvF { #1 ~ \text_lowercase:n { #2 } }
{ g_crefthe_contraction_rule_uppercase_ \languagename _tl }
{ #1 ~ \text_lowercase:n { #2 } }
}
{
\str_case_e:nvF { #1 ~ \text_lowercase:n { #2 } }
{ g_crefthe_contraction_rule_ \languagename _tl }
{ #1 ~ \text_lowercase:n { #2 } }
}
}
{ #1 ~ #2 }
}
}
\tl_gset:Nn \g_crefthe_contraction_rule_french_tl
{
{ à~le } { au }
{ à~les } { aux }
{ de~le } { du }
{ de~les } { des }
{ À~le } { Au }
{ À~les } { Aux }
{ De~le } { Du }
{ De~les } { Des }
}
\tl_gset:Nn \g_crefthe_contraction_rule_uppercase_french_tl
{
{ à~le } { Au }
{ à~les } { Aux }
{ de~le } { Du }
{ de~les } { Des }
{ À~le } { Au }
{ À~les } { Aux }
{ De~le } { Du }
{ De~les } { Des }
}
\tl_gset:Nn \g_crefthe_contraction_rule_italian_tl
{
{ a~il } { al }
{ a~lo } { allo }
{ a~l' } { all' }
{ a~la } { alla }
{ di~il } { del }
{ di~lo } { dello }
{ di~l' } { dell' }
{ di~la } { della }
{ da~il } { dal }
{ da~lo } { dallo }
{ da~l' } { dall' }
{ da~la } { dalla }
{ in~il } { nel }
{ in~lo } { nello }
{ in~l' } { nell' }
{ in~la } { nella }
{ su~il } { sul }
{ su~lo } { sullo }
{ su~l' } { sull' }
{ su~la } { sulla }
{ a~i } { ai }
{ a~gli } { agli }
{ a~le } { alle }
{ di~i } { dei }
{ di~gli } { degli }
{ di~le } { delle }
{ da~i } { dai }
{ da~gli } { dagli }
{ da~le } { dalle }
{ in~i } { nei }
{ in~gli } { negli }
{ in~le } { nelle }
{ su~i } { sui }
{ su~gli } { sugli }
{ su~le } { sulle }
{ A~il } { Al }
{ A~lo } { Allo }
{ A~l' } { All' }
{ A~la } { Alla }
{ Di~il } { Del }
{ Di~lo } { Dello }
{ Di~l' } { Dell' }
{ Di~la } { Della }
{ Da~il } { Dal }
{ Da~lo } { Dallo }
{ Da~l' } { Dall' }
{ Da~la } { Dalla }
{ In~il } { Nel }
{ In~lo } { Nello }
{ In~l' } { Nell' }
{ In~la } { Nella }
{ Su~il } { Sul }
{ Su~lo } { Sullo }
{ Su~l' } { Sull' }
{ Su~la } { Sulla }
{ A~i } { Ai }
{ A~gli } { Agli }
{ A~le } { Alle }
{ Di~i } { Dei }
{ Di~gli } { Degli }
{ Di~le } { Delle }
{ Da~i } { Dai }
{ Da~gli } { Dagli }
{ Da~le } { Dalle }
{ In~i } { Nei }
{ In~gli } { Negli }
{ In~le } { Nelle }
{ Su~i } { Sui }
{ Su~gli } { Sugli }
{ Su~le } { Sulle }
}
\tl_gset:Nn \g_crefthe_contraction_rule_uppercase_italian_tl
{
{ a~il } { Al }
{ a~lo } { Allo }
{ a~l' } { All' }
{ a~la } { Alla }
{ di~il } { Del }
{ di~lo } { Dello }
{ di~l' } { Dell' }
{ di~la } { Della }
{ da~il } { Dal }
{ da~lo } { Dallo }
{ da~l' } { Dall' }
{ da~la } { Dalla }
{ in~il } { Nel }
{ in~lo } { Nello }
{ in~l' } { Nell' }
{ in~la } { Nella }
{ su~il } { Sul }
{ su~lo } { Sullo }
{ su~l' } { Sull' }
{ su~la } { Sulla }
{ a~i } { Ai }
{ a~gli } { Agli }
{ a~le } { Alle }
{ di~i } { Dei }
{ di~gli } { Degli }
{ di~le } { Delle }
{ da~i } { Dai }
{ da~gli } { Dagli }
{ da~le } { Dalle }
{ in~i } { Nei }
{ in~gli } { Negli }
{ in~le } { Nelle }
{ su~i } { Sui }
{ su~gli } { Sugli }
{ su~le } { Sulle }
{ A~il } { Al }
{ A~lo } { Allo }
{ A~l' } { All' }
{ A~la } { Alla }
{ Di~il } { Del }
{ Di~lo } { Dello }
{ Di~l' } { Dell' }
{ Di~la } { Della }
{ Da~il } { Dal }
{ Da~lo } { Dallo }
{ Da~l' } { Dall' }
{ Da~la } { Dalla }
{ In~il } { Nel }
{ In~lo } { Nello }
{ In~l' } { Nell' }
{ In~la } { Nella }
{ Su~il } { Sul }
{ Su~lo } { Sullo }
{ Su~l' } { Sull' }
{ Su~la } { Sulla }
{ A~i } { Ai }
{ A~gli } { Agli }
{ A~le } { Alle }
{ Di~i } { Dei }
{ Di~gli } { Degli }
{ Di~le } { Delle }
{ Da~i } { Dai }
{ Da~gli } { Dagli }
{ Da~le } { Dalle }
{ In~i } { Nei }
{ In~gli } { Negli }
{ In~le } { Nelle }
{ Su~i } { Sui }
{ Su~gli } { Sugli }
{ Su~le } { Sulle }
}
\tl_gset:Nn \g_crefthe_contraction_rule_spanish_tl
{
{ a~el } { al }
{ de~el } { del }
{ A~el } { Al }
{ De~el } { Del }
}
\tl_gset:Nn \g_crefthe_contraction_rule_uppercase_spanish_tl
{
{ a~el } { Al }
{ de~el } { Del }
{ A~el } { Al }
{ De~el } { Del }
}
\tl_gset:Nn \g_crefthe_contraction_rule_portuguese_tl
{
{ a~o } { ao }
{ a~a } { à }
{ a~os } { aos }
{ a~as } { às }
{ de~o } { do }
{ de~a } { da }
{ de~os } { dos }
{ de~as } { das }
{ em~o } { no }
{ em~a } { na }
{ em~os } { nos }
{ em~as } { nas }
{ A~o } { Ao }
{ A~a } { À }
{ A~os } { Aos }
{ A~as } { Às }
{ De~o } { Do }
{ De~a } { Da }
{ De~os } { Dos }
{ De~as } { Das }
{ Em~o } { No }
{ Em~a } { Na }
{ Em~os } { Nos }
{ Em~as } { Nas }
}
\tl_gset:Nn \g_crefthe_contraction_rule_uppercase_portuguese_tl
{
{ a~o } { Ao }
{ a~a } { À }
{ a~os } { Aos }
{ a~as } { Às }
{ de~o } { Do }
{ de~a } { Da }
{ de~os } { Dos }
{ de~as } { Das }
{ em~o } { No }
{ em~a } { Na }
{ em~os } { Nos }
{ em~as } { Nas }
{ A~o } { Ao }
{ A~a } { À }
{ A~os } { Aos }
{ A~as } { Às }
{ De~o } { Do }
{ De~a } { Da }
{ De~os } { Dos }
{ De~as } { Das }
{ Em~o } { No }
{ Em~a } { Na }
{ Em~os } { Nos }
{ Em~as } { Nas }
}
\tl_gset:Nn \g_crefthe_contraction_rule_brazilian_tl
{
{ a~o } { ao }
{ a~a } { à }
{ a~os } { aos }
{ a~as } { às }
{ de~o } { do }
{ de~a } { da }
{ de~os } { dos }
{ de~as } { das }
{ em~o } { no }
{ em~a } { na }
{ em~os } { nos }
{ em~as } { nas }
{ A~o } { Ao }
{ A~a } { À }
{ A~os } { Aos }
{ A~as } { Às }
{ De~o } { Do }
{ De~a } { Da }
{ De~os } { Dos }
{ De~as } { Das }
{ Em~o } { No }
{ Em~a } { Na }
{ Em~os } { Nos }
{ Em~as } { Nas }
}
\tl_gset:Nn \g_crefthe_contraction_rule_uppercase_brazilian_tl
{
{ a~o } { Ao }
{ a~a } { À }
{ a~os } { Aos }
{ a~as } { Às }
{ de~o } { Do }
{ de~a } { Da }
{ de~os } { Dos }
{ de~as } { Das }
{ em~o } { No }
{ em~a } { Na }
{ em~os } { Nos }
{ em~as } { Nas }
{ A~o } { Ao }
{ A~a } { À }
{ A~os } { Aos }
{ A~as } { Às }
{ De~o } { Do }
{ De~a } { Da }
{ De~os } { Dos }
{ De~as } { Das }
{ Em~o } { No }
{ Em~a } { Na }
{ Em~os } { Nos }
{ Em~as } { Nas }
}
\endinput
%%
%% End of file `crefthe.sty'.
答案1
这是我对您的代码的挑剔(或多或少按照我在源代码中找到的顺序):
- 您不能真正调用
\cref
它,\crefthe_cref_original:n
因为它不只接受一个n
参数(有一个可选*
参数)。...:Nn
也是错误的,因为*
不是强制性的。\crefthe_cref_original:w
会更合适; - 我建议使用
\RenewCommandCopy
foroverwrite
,因为你不是复制一个简单的宏,而是复制组成命令的完整宏堆栈,以及需要一起复制的内部结构等(在这种情况下,不会发生任何糟糕的事情,但是你问对于编码风格...:) - 由于
overwrite
发生在包的末尾,因此无需使用钩子package/crefthe/after
,尽管我喜欢广告钩子,但只需将代码放在包的末尾即可; \tl_gset:Nn <tl var> { }
是\tl_gclear:N <tl var>
;- 您应该使用with (在编写/测试代码时,您可以加载然后执行以捕获此类错误);
\bool_gset_false:N
\g__crefthe_uppercase_bool
expl3
\RequirePackage[enable-debug]{expl3}
\debug_on:n { check-declarations, deprecation }
- 关于
\exp_args:Nx \str_case:nn \l__crefthe_prep_mode_tl
,它之所以有效是因为你对其进行了编码,但它在概念上是错误的(两次)。首先,标记列表\l__crefthe_prep_mode_tl
不包含expl3
意义上的“静态”标记列表,而是一个行动:它会根据 的值扩展为+
或,因此扩展其值不起作用,因为它需要多个扩展步骤才能成为“静态”内容。其次,因为你随后在 上使用函数,所以它会获取未完全扩展的标记列表内容并将它们转换为无意义的字符串。这里政治上正确的方法是创建一个函数,然后先完全扩展它,然后-
\languagename
V
\str_...
tl
\l__crefthe_prep_mode_tl
然后使用返回的字符串。代码中对此进行了注释; \crefthe
和\Crefthe
除了开头的布尔值和函数之外完全相同\crefthe_[Cc]ref_original:w
,因此你可以将它们合并到一个\__crefthe_cref_general:NNNnnN
函数中。代码重复通常是邪恶的! 和\crefthename
也一样\Crefthename
;\text_lowercase:n
相当慢,所以如果一个宏使用相同的\text_lowercase:n { <something> }
两次,我建议e
首先对其进行扩展,然后将所有内容传递给使用已经小写的文本的内部宏(我在中这样做了\crefthe_contraction:nn
);- 您必须
\tl_new:N <tl var>
在执行之前执行\tl_(g)set:Nn <tl var> { ... }
。不执行该操作是错误的(理论上)。在对它们\g_crefthe_contraction_rule_<language>_tl
执行操作之前,您的代码中未声明所有操作\tl_gset:Nn
。但是,这些操作永远不会改变,因此它们可以是常量,因此您可以改为使用以下方式定义它们\tl_const:Nn
; - 在
\crefthe_contraction:nn
你执行 时\tl_if_blank:eTF {#1}
,但是#1
是一个包含文本的变量,对文本进行- 或-expandtl
很危险。在将变量传递给 之前,使用 -expansion 将变量扩展为其值,然后使用。此外,如果你提前扩展某个变量,你可以根据需要扩展一次,并避免以后多次进行相同的扩展,从而使你的代码通常更快;e
x
V
\crefthe_contraction:nn
\tl_if_blank:nTF {#1}
- 这里您必须使用
\text_lowercase:n
而不是\str_foldcase:n
因为它\str_foldcase:n
不适À
用于诸如代码之类的字符串,而不是像重音字符这样的文本字符串; - 您的代码没有任何分组,所以似乎不需要全局分配,所以我把一切都变成了本地的;
- 您的代码做了一些有趣的事情,我不确定它(目前)是否可以更改。它设法通过利用以下事实进行比较
À le
:(\`A le
在 pdfTeX 中)前者最终会扩展为后者,但最终两者都会扩展为(相同的)乱码并被发现相等。理想情况下,应该有更好的方法来规范化\`A le
(À le
或反过来)并比较两者; - 您可以使用
\text_titlecase_first:n
将缩写的首字母大写,并避免定义基本上是每个缩写列表的副本。此外,brazilian
和portuguese
列表应该相同,因此您可以只定义一个并进行复制;
-
\str_case:nn
(并且扩展\str_case_e:nn
)不能有谓词版本( ),因为它会通过在其中注入任意标记来\str_case_p:nn
破坏布尔表达式的解析,因此从生成变体是错误的(并且如果按照第 5 点的建议启用调试,则会引发错误)。\bool_if:nTF
_p
\str_case_e:nn
我想就这些了...这是你的代码,完全被毁了:)
\begin{filecontents*}[overwrite]{crefthe.sty}
\NeedsTeXFormat{LaTeX2e}[2020-10-01]
\RequirePackage{l3keys2e}
\ProvidesExplPackage
{crefthe}
{2022/02/09} {}
{Cross referencing with proper definite articles}
\keys_define:nn { crefthe }
{
, overwrite .bool_set:N = \l__crefthe_overwrite_bool
, overwrite .initial:n = { false }
, unknown .code:n =
{ \PassOptionsToPackage { \CurrentOption } { cleveref } }
}
\ProcessKeysOptions { crefthe }
\RequirePackage { cleveref }
\NewCommandCopy \crefthe_cref_original:w \cref
\NewCommandCopy \crefthe_Cref_original:w \Cref
\NewCommandCopy \crefthe_crefname_original:w \crefname
\NewCommandCopy \crefthe_Crefname_original:w \Crefname
\str_new:N \l__crefthe_tmpa_str
\tl_new:N \l__crefthe_prep_once_tl
\tl_new:N \l__crefthe_prep_each_tl
\bool_new:N \l__crefthe_uppercase_bool
\NewDocumentCommand \crefthe { s t- t+ O{} m }
{
\bool_set_false:N \l__crefthe_uppercase_bool
\__crefthe_cref_general:NNNnnN #1 #2 #3 {#4} {#5} \crefthe_cref_original:w
}
\NewDocumentCommand \Crefthe { s t- t+ O{} m }
{
\bool_set_true:N \l__crefthe_uppercase_bool
\__crefthe_cref_general:NNNnnN #1 #2 #3 {#4} {#5} \crefthe_Cref_original:w
}
\cs_new_protected:Npn \__crefthe_cref_general:NNNnnN #1 #2 #3 #4 #5 #6
{
\bool_if:NTF #2
{ \tl_set:Nn \l__crefthe_prep_once_tl {#4} }
{
\bool_if:NTF #3
{ \tl_set:Nn \l__crefthe_prep_each_tl {#4} }
{
% \str_set:Nx fully expands \__crefthe_prep_mode: into a
% string, then \str_case:Vn compares the value of the
% resulting string:
\str_set:Nx \l__crefthe_tmpa_str { \__crefthe_prep_mode: }
\str_case:Vn \l__crefthe_tmpa_str
{
{ - } { \tl_set:Nn \l__crefthe_prep_once_tl {#4} }
{ + } { \tl_set:Nn \l__crefthe_prep_each_tl {#4} }
}
}
}
\bool_if:NTF #1
{ #6 * {#5} } % here #6 is \crefthe_cref_original:w or \crefthe_Cref_original:w
{ #6 {#5} }
\tl_gclear:N \l__crefthe_prep_each_tl
}
\cs_new:Npn \__crefthe_prep_mode:
{
\str_case:Vn { \languagename }
{
{french} { + }
{italian} { + }
{spanish} { - }
{portuguese} { + }
{brazilian} { + }
}
}
\NewDocumentCommand \crefthename { m O{} m O{} m }
{
\__crefthe_name_general:nnnnnNN {#1} {#2} {#3} {#4} {#5}
c \crefthe_crefname_original:w
}
\NewDocumentCommand \Crefthename { m O{} m O{} m }
{
\__crefthe_name_general:nnnnnNN {#1} {#2} {#3} {#4} {#5}
C \crefthe_Crefname_original:w
}
\cs_new_protected:Npn \__crefthe_name_general:nnnnnNN #1 #2 #3 #4 #5 #6 #7
{
% #6 is c or C
% #7 is \crefthe_crefname_original:w or \crefthe_Crefname_original:w
\tl_if_blank:nTF {#2}
{
#7 {#1} {#3} {#5}
\cs_set:cn { #6ref_#1_format:nnn } { ##2 #3 ~ ##1 ##3 }
\cs_set:cn { #6ref_#1_format_first:nnn } { ##2 #5 ~ ##1 ##3 }
}
{
#7 {#1} { \crefthemark {#2} #3 } { \crefthemark {#4} #5 }
\cs_set:cn { #6ref_#1_format:nnn } { \crefthemark {#2} ##2 #3 ~ ##1 ##3 }
\cs_set:cn { #6ref_#1_format_first:nnn } { \crefthemark {#4} ##2 #5 ~ ##1 ##3 }
}
\AddToHook { begindocument }
{
\cs_set_eq:cc { #6ref@ #1 @format } { #6ref_#1_format:nnn }
\cs_set_eq:cc { #6ref@ #1 @format@first } { #6ref_#1_format_first:nnn }
}
}
\cs_generate_variant:Nn \text_lowercase:n { V }
\NewDocumentCommand \crefthemark { m }
{
\crefthe_contraction:Ve \l__crefthe_prep_each_tl
{ \crefthe_contraction:Vn \l__crefthe_prep_once_tl {#1} }
\tl_gclear:N \l__crefthe_prep_once_tl
\tl_set:Nx \l__crefthe_prep_each_tl
{ \text_lowercase:V \l__crefthe_prep_each_tl }
\str_if_eq:eeF { \str_tail:n {#1} } { ' } { ~ }
\bool_set_false:N \l__crefthe_uppercase_bool
}
\prg_generate_conditional_variant:Nnn \str_case_e:nn { nv } { T, F, TF }
\cs_new:Npn \crefthe_contraction:nn #1#2
{
\exp_args:Ne \__crefthe_contraction:nnn
{ \text_lowercase:n {#2} } {#1} {#2}
}
\cs_generate_variant:Nn \crefthe_contraction:nn { V, Ve }
\cs_new:Npn \eshow:n #1 { \exp_args:No \use_none:n { \ERR <#1> } }
\cs_new:Npn \__crefthe_contraction:nnn #1 #2 #3
{
% #1 is \text_lowercase:n {#3}
\tl_if_blank:nTF {#2}
{#3}
{
\tl_if_exist:cTF { c_crefthe_contraction_rule_ \languagename _tl }
{
\exp_args:Ne \__crefthe_contraction_uppercase:n
{
% This e-expansion here is wrong, but the code doesn't work
% without it. See point 13 in my answer...
% vv
\str_case_e:nvF { #2~#1 }
{ c_crefthe_contraction_rule_ \languagename _tl }
{ #2~#1 }
}
}
{ #2~#3 }
}
}
\cs_new:Npn \__crefthe_contraction_uppercase:n #1
{
\bool_if:NTF \l__crefthe_uppercase_bool
{ \text_titlecase_first:n }
{ \use:n }
{#1}
}
\bool_if:NT \l__crefthe_overwrite_bool
{
\RenewCommandCopy \cref \crefthe
\RenewCommandCopy \Cref \Crefthe
\RenewCommandCopy \crefname \crefthename
\RenewCommandCopy \Crefname \Crefthename
}
\tl_const:Nn \c_crefthe_contraction_rule_french_tl
{
{ à~le } { au }
{ à~les } { aux }
{ de~le } { du }
{ de~les } { des }
{ À~le } { Au }
{ À~les } { Aux }
{ De~le } { Du }
{ De~les } { Des }
}
\tl_const:Nn \c_crefthe_contraction_rule_italian_tl
{
{ a~il } { al }
{ a~lo } { allo }
{ a~l' } { all' }
{ a~la } { alla }
{ di~il } { del }
{ di~lo } { dello }
{ di~l' } { dell' }
{ di~la } { della }
{ da~il } { dal }
{ da~lo } { dallo }
{ da~l' } { dall' }
{ da~la } { dalla }
{ in~il } { nel }
{ in~lo } { nello }
{ in~l' } { nell' }
{ in~la } { nella }
{ su~il } { sul }
{ su~lo } { sullo }
{ su~l' } { sull' }
{ su~la } { sulla }
{ a~i } { ai }
{ a~gli } { agli }
{ a~le } { alle }
{ di~i } { dei }
{ di~gli } { degli }
{ di~le } { delle }
{ da~i } { dai }
{ da~gli } { dagli }
{ da~le } { dalle }
{ in~i } { nei }
{ in~gli } { negli }
{ in~le } { nelle }
{ su~i } { sui }
{ su~gli } { sugli }
{ su~le } { sulle }
{ A~il } { Al }
{ A~lo } { Allo }
{ A~l' } { All' }
{ A~la } { Alla }
{ Di~il } { Del }
{ Di~lo } { Dello }
{ Di~l' } { Dell' }
{ Di~la } { Della }
{ Da~il } { Dal }
{ Da~lo } { Dallo }
{ Da~l' } { Dall' }
{ Da~la } { Dalla }
{ In~il } { Nel }
{ In~lo } { Nello }
{ In~l' } { Nell' }
{ In~la } { Nella }
{ Su~il } { Sul }
{ Su~lo } { Sullo }
{ Su~l' } { Sull' }
{ Su~la } { Sulla }
{ A~i } { Ai }
{ A~gli } { Agli }
{ A~le } { Alle }
{ Di~i } { Dei }
{ Di~gli } { Degli }
{ Di~le } { Delle }
{ Da~i } { Dai }
{ Da~gli } { Dagli }
{ Da~le } { Dalle }
{ In~i } { Nei }
{ In~gli } { Negli }
{ In~le } { Nelle }
{ Su~i } { Sui }
{ Su~gli } { Sugli }
{ Su~le } { Sulle }
}
\tl_const:Nn \c_crefthe_contraction_rule_spanish_tl
{
{ a~el } { al }
{ de~el } { del }
{ A~el } { Al }
{ De~el } { Del }
}
\tl_const:Nn \c_crefthe_contraction_rule_portuguese_tl
{
{ a~o } { ao }
{ a~a } { à }
{ a~os } { aos }
{ a~as } { às }
{ de~o } { do }
{ de~a } { da }
{ de~os } { dos }
{ de~as } { das }
{ em~o } { no }
{ em~a } { na }
{ em~os } { nos }
{ em~as } { nas }
{ A~o } { Ao }
{ A~a } { À }
{ A~os } { Aos }
{ A~as } { Às }
{ De~o } { Do }
{ De~a } { Da }
{ De~os } { Dos }
{ De~as } { Das }
{ Em~o } { No }
{ Em~a } { Na }
{ Em~os } { Nos }
{ Em~as } { Nas }
}
\tl_const:Nx \c_crefthe_contraction_rule_brazilian_tl
{ \exp_not:V \c_crefthe_contraction_rule_portuguese_tl }
\endinput
%%
%% End of file `crefthe.sty'.
\end{filecontents*}
\documentclass{article}
\usepackage{amsthm}
\usepackage{hyperref}
\usepackage[nameinlink,french]{crefthe}
\usepackage[french]{babel}
\newtheorem{thm}{Théorème}
\newtheorem{thmn}{Théorème facile}
\crefthename{thm}[le]{théorème}[les]{théorèmes}
\crefthename{thmn}[le]{théorème facile}[les]{théorèmes faciles}
\Crefthename{thm}[Le]{théorème}[Les]{théorèmes}
\Crefthename{thmn}[Le]{théorème facile}[Les]{théorèmes faciles}
\begin{document}
\begin{thm}\label{thm1}
some text.
\end{thm}
\begin{thm}\label{thm2}
more text.
\end{thm}
\begin{thmn}\label{thmn1}
more other text.
\end{thmn}
- Single one -
\crefthe[\`A]{thm1}, \crefthe[\`a]{thm1}
\crefthe[À]{thm1}, \crefthe[à]{thm1}
\Crefthe[à]{thm1}, \crefthe[à]{thm1}
\Crefthe[À]{thm1}, \crefthe[à]{thm1}
\crefthe[de]{thm1}
\Crefthe[de]{thm1}
- Multiple ones -
\crefthe[À]{thm1,thmn1}
\Crefthe[À]{thm1,thmn1}
\crefthe[À]{thm1,thm2}
\Crefthe[À]{thm1,thm2}
\Crefthe[De]{thm1,thm2,thmn1}
\Crefthe{thm1,thm2,thmn1}
\crefthe{thm1,thm2}
\end{document}
答案2
作为参考,以下是当前(截至 2022-02-10)的更正版本:
\NeedsTeXFormat{LaTeX2e}[2020-10-01]
\RequirePackage{l3keys2e}
\ProvidesExplPackage
{crefthe}
{2022/02/10} {}
{Cross referencing with proper definite articles}
\keys_define:nn { crefthe }
{
, overwrite .bool_set:N = \l__crefthe_overwrite_bool
, overwrite .initial:n = { false }
, unknown .code:n =
{ \PassOptionsToPackage { \CurrentOption } { cleveref } }
}
\ProcessKeysOptions { crefthe }
\RequirePackage { cleveref }
\NewCommandCopy \crefthe_cref_original:w \cref
\NewCommandCopy \crefthe_Cref_original:w \Cref
\NewCommandCopy \crefthe_crefname_original:w \crefname
\NewCommandCopy \crefthe_Crefname_original:w \Crefname
\str_new:N \l__crefthe_tmpa_str
% \l__crefthe_prep_once_tl is for the "-" mode,
% that only passes the preposition to the first definite article;
% \l__crefthe_prep_each_tl is for the "+" mode,
% that passes the preposition to every definite article.
\tl_new:N \l__crefthe_prep_once_tl
\tl_new:N \l__crefthe_prep_each_tl
\bool_new:N \l__crefthe_uppercase_bool
\NewDocumentCommand \crefthe { s t- t+ O{} m }
{
\bool_set_false:N \l__crefthe_uppercase_bool
\__crefthe_cref_general:NNNnnN #1 #2 #3 { #4 } { #5 } \crefthe_cref_original:w
}
\NewDocumentCommand \Crefthe { s t- t+ O{} m }
{
\bool_set_true:N \l__crefthe_uppercase_bool
\__crefthe_cref_general:NNNnnN #1 #2 #3 { #4 } { #5 } \crefthe_Cref_original:w
}
\cs_new_protected:Npn \__crefthe_cref_general:NNNnnN #1 #2 #3 #4 #5 #6
{
\bool_if:NTF #2
{ \tl_set:Nn \l__crefthe_prep_once_tl { #4 } }
{
\bool_if:NTF #3
{ \tl_set:Nn \l__crefthe_prep_each_tl { #4 } }
{
% \str_set:Nx fully expands \__crefthe_prep_mode: into a
% string, then \str_case:Vn compares the value of the
% resulting string:
\str_set:Nx \l__crefthe_tmpa_str { \__crefthe_prep_mode: }
\str_case:Vn \l__crefthe_tmpa_str
{
{ - } { \tl_set:Nn \l__crefthe_prep_once_tl { #4 } }
{ + } { \tl_set:Nn \l__crefthe_prep_each_tl { #4 } }
}
}
}
\bool_if:NTF #1
{ #6 * { #5 } } % here #6 is \crefthe_cref_original:w or \crefthe_Cref_original:w
{ #6 { #5 } }
\tl_gclear:N \l__crefthe_prep_each_tl
}
% \__crefthe_prep_mode: defines the default mode for supported languages
\cs_new:Npn \__crefthe_prep_mode:
{
\str_case:Vn \languagename
{
{french} { + }
{italian} { + }
{spanish} { - }
{portuguese} { + }
{brazilian} { + }
}
}
\NewDocumentCommand \crefthename { m O{} m O{} m }
{
\__crefthe_name_general:nnnnnNN { #1 } { #2 } { #3 } { #4 } { #5 }
c \crefthe_crefname_original:w
}
\NewDocumentCommand \Crefthename { m O{} m O{} m }
{
\__crefthe_name_general:nnnnnNN { #1 } { #2 } { #3 } { #4 } { #5 }
C \crefthe_Crefname_original:w
}
\cs_new_protected:Npn \__crefthe_name_general:nnnnnNN #1 #2 #3 #4 #5 #6 #7
{
% #6 is c or C
% #7 is \crefthe_crefname_original:w or \crefthe_Crefname_original:w
\tl_if_blank:nTF { #2 }
{
#7 { #1 } { #3 } { #5 }
\cs_set:cn { #6ref_#1_format:nnn } { ##2 #3 ~ ##1 ##3 }
\cs_set:cn { #6ref_#1_format_first:nnn } { ##2 #5 ~ ##1 ##3 }
}
{
#7 { #1 } { \crefthemark { #2 } #3 } { \crefthemark { #4 } #5 }
\cs_set:cn { #6ref_#1_format:nnn } { \crefthemark { #2 } ##2 #3 ~ ##1 ##3 }
\cs_set:cn { #6ref_#1_format_first:nnn } { \crefthemark { #4 } ##2 #5 ~ ##1 ##3 }
}
\hook_gput_code:nnn { begindocument } { crefthe }
{
\cs_set_eq:cc { #6ref@ #1 @format } { #6ref_#1_format:nnn }
\cs_set_eq:cc { #6ref@ #1 @format@first } { #6ref_#1_format_first:nnn }
}
}
\cs_generate_variant:Nn \text_lowercase:n { V }
\NewDocumentCommand \crefthemark { m }
{
\crefthe_contraction:Ve \l__crefthe_prep_each_tl
{ \crefthe_contraction:Vn \l__crefthe_prep_once_tl { #1 } }
\tl_gclear:N \l__crefthe_prep_once_tl
\tl_set:Nx \l__crefthe_prep_each_tl
{ \text_lowercase:V \l__crefthe_prep_each_tl }
\str_if_eq:eeF { \str_tail:n { #1 } } { ' } { ~ }
\bool_set_false:N \l__crefthe_uppercase_bool
}
\prg_generate_conditional_variant:Nnn \str_case_e:nn { nv } { T, F, TF }
\cs_new:Npn \crefthe_contraction:nn #1#2
{
\exp_args:Ne \__crefthe_contraction:nnn
{ \text_lowercase:n { #2 } } { #1 } { #2 }
}
\cs_generate_variant:Nn \crefthe_contraction:nn { V, Ve }
\cs_new:Npn \__crefthe_contraction:nnn #1 #2 #3
{
% #1 is \text_lowercase:n { #3 }
% #2 is the preposition
\tl_if_blank:nTF { #2 }
{ #3 }
{
\tl_if_exist:cTF { c_crefthe_contraction_rule_ \languagename _tl }
{
\exp_args:Ne \__crefthe_conditional_uppercase:n
{
\str_case_e:nvF { #2~#1 }
{ c_crefthe_contraction_rule_ \languagename _tl }
{ #2~#1 }
}
}
{ #2~#3 }
}
}
\cs_new:Npn \__crefthe_conditional_uppercase:n #1
{
\bool_if:NTF \l__crefthe_uppercase_bool
{ \text_titlecase_first:n }
{ \use:n }
{ #1 }
}
\hook_gput_code:nnn { begindocument/end } { crefthe }
{
\bool_if:NT \l__crefthe_overwrite_bool
{
\RenewCommandCopy \cref \crefthe
\RenewCommandCopy \Cref \Crefthe
\RenewCommandCopy \crefname \crefthename
\RenewCommandCopy \Crefname \Crefthename
}
}
\tl_const:Nn \c_crefthe_contraction_rule_french_tl
{
{ à~le } { au }
{ à~les } { aux }
{ de~le } { du }
{ de~les } { des }
{ À~le } { Au }
{ À~les } { Aux }
{ De~le } { Du }
{ De~les } { Des }
}
\tl_const:Nn \c_crefthe_contraction_rule_italian_tl
{
{ a~il } { al }
{ a~lo } { allo }
{ a~l' } { all' }
{ a~la } { alla }
{ di~il } { del }
{ di~lo } { dello }
{ di~l' } { dell' }
{ di~la } { della }
{ da~il } { dal }
{ da~lo } { dallo }
{ da~l' } { dall' }
{ da~la } { dalla }
{ in~il } { nel }
{ in~lo } { nello }
{ in~l' } { nell' }
{ in~la } { nella }
{ su~il } { sul }
{ su~lo } { sullo }
{ su~l' } { sull' }
{ su~la } { sulla }
{ a~i } { ai }
{ a~gli } { agli }
{ a~le } { alle }
{ di~i } { dei }
{ di~gli } { degli }
{ di~le } { delle }
{ da~i } { dai }
{ da~gli } { dagli }
{ da~le } { dalle }
{ in~i } { nei }
{ in~gli } { negli }
{ in~le } { nelle }
{ su~i } { sui }
{ su~gli } { sugli }
{ su~le } { sulle }
{ A~il } { Al }
{ A~lo } { Allo }
{ A~l' } { All' }
{ A~la } { Alla }
{ Di~il } { Del }
{ Di~lo } { Dello }
{ Di~l' } { Dell' }
{ Di~la } { Della }
{ Da~il } { Dal }
{ Da~lo } { Dallo }
{ Da~l' } { Dall' }
{ Da~la } { Dalla }
{ In~il } { Nel }
{ In~lo } { Nello }
{ In~l' } { Nell' }
{ In~la } { Nella }
{ Su~il } { Sul }
{ Su~lo } { Sullo }
{ Su~l' } { Sull' }
{ Su~la } { Sulla }
{ A~i } { Ai }
{ A~gli } { Agli }
{ A~le } { Alle }
{ Di~i } { Dei }
{ Di~gli } { Degli }
{ Di~le } { Delle }
{ Da~i } { Dai }
{ Da~gli } { Dagli }
{ Da~le } { Dalle }
{ In~i } { Nei }
{ In~gli } { Negli }
{ In~le } { Nelle }
{ Su~i } { Sui }
{ Su~gli } { Sugli }
{ Su~le } { Sulle }
}
\tl_const:Nn \c_crefthe_contraction_rule_spanish_tl
{
{ a~el } { al }
{ de~el } { del }
{ A~el } { Al }
{ De~el } { Del }
}
\tl_const:Nn \c_crefthe_contraction_rule_portuguese_tl
{
{ a~o } { ao }
{ a~a } { à }
{ a~os } { aos }
{ a~as } { às }
{ de~o } { do }
{ de~a } { da }
{ de~os } { dos }
{ de~as } { das }
{ em~o } { no }
{ em~a } { na }
{ em~os } { nos }
{ em~as } { nas }
{ A~o } { Ao }
{ A~a } { À }
{ A~os } { Aos }
{ A~as } { Às }
{ De~o } { Do }
{ De~a } { Da }
{ De~os } { Dos }
{ De~as } { Das }
{ Em~o } { No }
{ Em~a } { Na }
{ Em~os } { Nos }
{ Em~as } { Nas }
}
\tl_const:Nx \c_crefthe_contraction_rule_brazilian_tl
{ \exp_not:V \c_crefthe_contraction_rule_portuguese_tl }
\endinput
%%
%% End of file `crefthe.sty'.