我希望能够重新定义一些应该在序言中定义的东西。
在这个例子中,关于这个问题:
交叉引用:更多子级别和预设,我想重新定义cleveref
包的 \crefrangelabelformat,但是不起作用,请参阅 MWE 及其输出。
\documentclass{article}
\usepackage{indentfirst}
\usepackage[hidelinks]{hyperref}
\usepackage{cleveref}
\usepackage{xstring}
\usepackage{philex}
%MyStripToColon (requires xstring)
\newcommand{\mystriptocolon}[2]{\StrCut{#1}{.}{\myonea}{\myoneb}%
\StrCut{#2}{.}{\mytwoa}{\mytwob}%
\IfStrEq{\myonea}{\mytwoa}{\mytwob}{#2}}
% Cleveref Label Formatting
\crefname{ExNo}{}{}
\crefname{SubExNo}{}{}
\crefname{SubSubExNo}{}{}
\creflabelformat{ExNo}{#2#1#3} % The output of the \cref command doesn't include parentheses.
\creflabelformat{SubExNo}{#2#1#3}
\creflabelformat{SubSubExNo}{#2#1#3}
\crefrangelabelformat{ExNo}{#3#1#4--#5#2#6}
\crefrangelabelformat{SubExNo}{#3#1#4--#5\crefstripprefix{#1}{#2}#6}
\crefrangelabelformat{SubSubExNo}{#3#1#4--#5\mystriptocolon{#1}{#2}#6}
\newcommand{\crefrangeconjunction}{–}
\begin{document}
% Philex Label Formatting
\phildashes{}{.}
\subformat{a}{}{.}
\subsubformat{i}{(}{)}
\lb{main1}{This is main1.
\lba{sub1}{This is sub1.
\lba{subsub11}{This is subsub11.}
\lbz{subsub12}{This is subsub12.}}
\lbz{sub2}{This is sub2.
\lba{subsub21}{This is subsub21.}
\lbz{subsub22}{This is subsub22.}}}
\lb{main2}{This is main2.}
\textbackslash mystriptocolon works like a charm:
\vspace{6pt}
\textbackslash crefrange\{sub1\}\{sub2\} \textrightarrow{} \crefrange{sub1}{sub2}
\vspace{6pt}
\textbackslash crefrange\{subsub11\}\{subsub12\} \textrightarrow{} \crefrange{subsub11}{subsub12}
\vspace{6pt}
\textbf{Now I change label formatting.}
\phildashes{.}{}
\subformat{1}{}{.}
\subsubformat{a}{}{.}
\lb{main3}{This is main3.
\lba{sub31}{This is sub31.
\lba{subsub311}{This is subsub311.}
\lbz{subsub312}{This is subsub312.}}
\lbz{sub32}{This is sub32.}}
\vspace{6pt}
\textbf{Trying to redefine \textbackslash crefrangelabelformat in order for the new subsublevel format to be supported, now that there is no separator:}
\vspace{6pt}
\textbackslash crefrangelabelformat\{SubSubExNo\}\{\#3\#1\#4--\#5\textbackslash crefstripprefix\{\#1\}\{\#2\}\#6\}
\crefrangelabelformat{SubSubExNo}{#3#1#4--#5\crefstripprefix{#1}{#2}#6}
\textbackslash crefrange\{subsub311\}\{subsub312\} \textrightarrow{} \crefrange{subsub311}{subsub312}
\vspace{6pt}
As you can see, the new \textbackslash crefrangelabelformat has not been taken into account and I cannot use \textbackslash crefstripprefix, I would like to obtain 3.1a--b but the 1 is repeated.
\end{document}
答案1
评论:
philex 包的 hyperref 支持非常混乱:
- 根本无法确保每个命名的超链接目的地/目标/锚点都有唯一的名称。
因此,您会收到很多警告,就像pdfTeX warning (ext4): destination with the same identifier (name{altsub.2}) has been already used, duplicate ignored
使用基于 pdfTeX 的 TeX 引擎时一样。所有 TeX 引擎的另一个后果是根本无法确保超链接指向 pdf 文档中的正确位置。原因之一是:可能会发生多次计数器重置。使用 hyperref 时,许多目的地/目标/锚点的名称都会在\refstepcounter
执行时自动创建。这些目的地名称来自计数器的名称和递增的值。因此,如果计数器的值被重置,则不再能确保目的地/目标/锚点名称的唯一性。这个问题可能可以修复:加载 hyperref 时,每个计数器除了众所周知的-macro 之外,还有一个关联的-macro,表示当相关计数器递增时应如何创建目的地/目标/锚点的名称。似乎 philex 的软件包维护者没有考虑到 -macros的维护。\the⟨counter⟩
\theH⟨counter⟩
\refstepcounter
\theH⟨counter⟩
- 在 CTAN 上,你会得到一个 .sty 文件,其中的换行看起来很奇怪,在某些地方你会发现很多不必要的东西
%
,而其他地方%
似乎缺失了一些东西。我不会深入研究该包的代码。但我建议在修复之前不要使用它。
- 根本无法确保每个命名的超链接目的地/目标/锚点都有唯一的名称。
你说:
“我希望能够重新定义一些本应在序言中定义的东西。”
为什么不重新定义,而是在序言中定义事物,使其行为取决于例如反标志的值?
如果这样做,您可以通过将表示反标志的宏重新定义为另一个值来选择行为。下面的示例提供了一个用于选择几个括号嵌套的宏参数之一的宏:
\ExtractKthArg{⟨TeX-⟨number⟩-quantity of value K⟩}% {⟨tokens in case list of undelimited arguments doesn't have a K-th argument⟩}% {⟨list of undelimited arguments⟩}
如果⟨无界参数列表⟩:
是否提供⟨如果未限定参数列表没有第 K 个参数,则使用 tokens⟩.
假设有第 K 个参数⟨无界参数列表⟩:
传递第 K 个参数,并删除一层括号。以下示例
\StyleFlag
定义了一个宏。扩展\StyleFlag
应始终产生有效的 TeX-⟨number⟩-quantity。通过下面的示例,定义了一个宏,以便您可以轻松地为分配另一个值。
\SetStyleFlag{⟨TeX-⟨number⟩-quantity⟩}
\StyleFlag
下面的示例
\SelectAccordingToStyleFlag
提供了一个宏。它在内部使用\ExtractKthArg
with\StyleFlag
作为其⟨TeX-⟨number⟩-K 值的数量⟩-argument。语法为\SelectAccordingToStyleFlag
:\SelectAccordingToStyleFlag{⟨Default-Tokens⟩}{% {⟨Tokens if value of \StyleFlag is 1⟩}% {⟨Tokens if value of \StyleFlag is 2⟩}% {⟨Tokens if value of \StyleFlag is 3⟩}% ...% }%
⟨默认代币⟩如果表示值 K,则使用
\StyleFlag
,以便以下列表没有第 K 个参数。例如,您可以在序言中
\SelectAccordingToStyleFlag
设置一些内容时使用。\crefrangelabelformat
在文档环境中,您可以
\crefrange
通过将 style-flag 设置为另一个值来更改相应 的行为\SetStyleFlag
。
下面的例子仅仅展示了解决 cleveref和macros 不能在文档环境中重新定义这个问题的一种方法。\cref...name
\cref...format
下面的例子没有解决 philex 包在正确的超链接支持方面的缺陷。
\makeatletter
%% Code for \ExtractKthArg
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@Exchange,
%% \UD@stopromannumeral, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
\expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArg{<TeX-<number>-quantity of value K>}%
%% {<tokens in case list of undelimited args doesn't have a k-th argumnent>}%
%% {<list of undelimited args>} %
%%
%% In case there is no K-th argument in <list of indelimited args> :
%% Does deliver <tokens in case list of undelimited args doesn't have a k-th argumnent.
%% In case there is a K-th argument in <list of indelimited args> :
%% Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%% \ExtractKthArg{0}{not available}{ABCDE} yields: not available
%%
%% \ExtractKthArg{3}{not available}{ABCDE} yields: C
%%
%% \ExtractKthArg{3}{not available}{AB{CD}E} yields: CD
%%
%% \ExtractKthArg{4}{not available}{{001}{002}{003}{004}{005}} yields: 004
%%
%% \ExtractKthArg{6}{not available}{{001}{002}{003}} yields: not available
%%
%%=============================================================================
\newcommand\ExtractKthArg[2]{%
\romannumeral%
% #1: <integer number K>
% #2: <action if there is no K-th argument>
\expandafter\UD@ExtractKthArgCheck
\expandafter{\romannumeral\number\number#1 000}{#2}%
}%
\newcommand\UD@ExtractKthArgCheck[3]{%
\UD@CheckWhetherNull{#1}{\UD@stopromannumeral#2}{% empty
\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}{#3}%
}%
}%
\begingroup
\def\UD@ExtractFirstArgLoop#1{%
\endgroup
\@ifdefinable\UD@RemoveTillFrozenrelax{%
\long\def\UD@RemoveTillFrozenrelax##1##2#1{{##1}}%
}%
\newcommand\UD@ExtractKthArgLoop[3]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo##3{}.}{\UD@stopromannumeral##2}{%
\UD@CheckWhetherNull{##1}{%
\UD@ExtractFirstArgLoop{##3#1}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}##3}%
{\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}##1}{##2}}%
}%
}%
}%
}%
\expandafter\expandafter\expandafter\UD@ExtractFirstArgLoop
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\ifnum0=0\fi}%
%% Usage of frozen-\relax as delimiter is for speeding things up by reducing the
%% amount of iterations needed. I chose frozen-\relax because David Carlisle
%% pointed out in <https://tex.stackexchange.com/a/578877>
%% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be
%% affected by \uppercase/\lowercase.
%%
%% \UD@ExtractFirstArg's argument may contain frozen-\relax:
%% The only effect is that internally more iterations are needed for
%% obtaining the result.
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\expandafter\UD@stopromannumeral\UD@firstoftwo#1{}}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}}%
}%
%% End of code for \ExtractKthArg.
\makeatother
%==============================================================================
% \SelectAccordingToStyleFlag
%==============================================================================
%
% Syntax:
%
% \SetStyleFlag{1} or \SetStyleFlag{2} or \SetStyleFlag{3} or ....
%
% \SelectAccordingToStyleFlag{<Default-Tokens>}{%
% {<Tokens if value of \StyleFlag is 1>}%
% {<Tokens if value of \StyleFlag is 2>}%
% {<Tokens if value of \StyleFlag is 3>}%
% ...%
% }%
%
\makeatletter
\newcommand\StyleFlag{1}%
\newcommand\SetStyleFlag[1]{\@bsphack\def\StyleFlag{#1}\@esphack}%
\newcommand\SelectAccordingToStyleFlag{%
\ExtractKthArg{\StyleFlag}%
}%
\makeatother
%==============================================================================
\documentclass{article}
\usepackage{indentfirst}
\usepackage[hyper]{philex}
\usepackage[hidelinks]{hyperref}
\usepackage{cleveref}
\usepackage{xstring}
%% Enable the following lines to see the coming into being of duplicate
%% destination/target/anchor-names more explicitly in the console-output - the
%% problem about warnings of pattern
%% pdfTeX warning (ext4): destination with the same identifier (name{altsubsub.1})
%% has been already used, duplicate ignored
%% still needs to be fixed by fixing what the macros coming from the philex-package
%% do. Probably by taking \theH<counter>-macros associated to philex's counters
%% into account:
%\makeatletter
%\AtBeginDocument{%
% \let\oldhypertarget\hypertarget
% \def\hypertarget#1{\message{^^J!!!Target-Name: #1^^J}\oldhypertarget{#1}}%
% \let\oldrefstepcounter\refstepcounter
% \def\refstepcounter{\message{^^J!!!Href: \detokenize\expandafter{\@currentHref}^^J}\oldrefstepcounter}%
%}%
%\makeatother
%MyStripToColon (requires xstring)
\newcommand{\mystriptocolon}[2]{\StrCut{#1}{.}{\myonea}{\myoneb}%
\StrCut{#2}{.}{\mytwoa}{\mytwob}%
\IfStrEq{\myonea}{\mytwoa}{\mytwob}{#2}%
}
% Cleveref Label Formatting
\crefname{ExNo}{}{}
\crefname{SubExNo}{}{}
\crefname{SubSubExNo}{}{}
\creflabelformat{ExNo}{#2#1#3} % The output of the \cref command doesn't include parentheses.
\creflabelformat{SubExNo}{#2#1#3}
\creflabelformat{SubSubExNo}{#2#1#3}
\crefrangelabelformat{ExNo}{#3#1#4--#5#2#6}
\crefrangelabelformat{SubExNo}{#3#1#4--#5\crefstripprefix{#1}{#2}#6}
\crefrangelabelformat{SubSubExNo}{%
\SelectAccordingToStyleFlag{#3#1#4--#5\mystriptocolon{#1}{#2}#6}{% <- default-format
{#3#1#4--#5\mystriptocolon{#1}{#2}#6}% <- Format if value of \StyleFlag is 1
{#3#1#4--#5\crefstripprefix{#1}{#2}#6}% <- Format if value of \StyleFlag is 2
% Append more if \StyleFlag can also be 3 or 4 or etc
}%
}%
\newcommand{\crefrangeconjunction}{–}
\begin{document}
% Philex Label Formatting
\phildashes{}{.}
\subformat{a}{}{.}
\subsubformat{i}{(}{)}
\lb{main1}{This is main1.
\lba{sub1}{This is sub1.
\lba{subsub11}{This is subsub11.}
\lbz{subsub12}{This is subsub12.}}
\lbz{sub2}{This is sub2.
\lba{subsub21}{This is subsub21.}
\lbz{subsub22}{This is subsub22.}}}
\lb{main2}{This is main2.}
\verb|\mystriptocolon| works like a charm:
\vspace{6pt}
\SetStyleFlag{1}%
\verb|\crefrange{sub1}{sub2}| \textrightarrow{} \crefrange{sub1}{sub2}
\vspace{6pt}
\verb|\crefrange{subsub11}{subsub12}| \textrightarrow{} \crefrange{subsub11}{subsub12}
\vspace{6pt}
\textbf{The philex-formatting is changed:}
\phildashes{.}{}
\subformat{1}{}{.}
\subsubformat{a}{}{.}
\lb{main3}{This is main3.
\lba{sub31}{This is sub31.
\lba{subsub311}{This is subsub311.}
\lbz{subsub312}{This is subsub312.}}
\lbz{sub32}{This is sub32.}}
\vspace{6pt}
\textbf{The Style-flag is changed from 1 to 2 to have other branch of
\texttt{\string\crefrangelabelformat\string{SubSubExNo\string}} in effect:}
\vspace{6pt}
\verb|\SetStyleFlag{2}|\SetStyleFlag{2}%
\verb|\crefrange{subsub311}{subsub312}| \textrightarrow{} \crefrange{subsub311}{subsub312}
\vspace{6pt}
As you can see, you obtain 3.1a--b without the 1 being repeated.
\end{document}
答案2
我将反过来看待这个问题:
默认使用 \crefstripprefix,即放弃
xstring
的\StrCut
做法;refcount
必要\getrefbykeydefault
时使用(来源:Ulrich Diez)https://tex.stackexchange.com/a/577464/262813)
\documentclass{article}
\usepackage{indentfirst}
\usepackage[hidelinks]{hyperref}
\usepackage{cleveref}
\usepackage{philex}
\setlength{\parskip}{1ex}
% Cleveref Label Formatting
\crefname{ExNo}{}{}
\crefname{SubExNo}{}{}
\crefname{SubSubExNo}{}{}
\creflabelformat{ExNo}{#2#1#3}
\creflabelformat{SubExNo}{#2#1#3}
\creflabelformat{SubSubExNo}{#2#1#3}
\crefrangelabelformat{ExNo}{#3#1#4--#5#2#6}
\crefrangelabelformat{SubExNo}{#3#1#4--#5\crefstripprefix{#1}{#2}#6}
\crefrangelabelformat{SubSubExNo}{#3#1#4--#5\crefstripprefix{#1}{#2}#6}
\newcommand{\crefrangeconjunction}{–}
% Skips everything before the dot.
\makeatletter
\@ifdefinable\gobbletodot{\long\def\gobbletodot#1.{}}% refcount package
\newcommand\delbefdot[1]{%
\ifcat$\detokenize\expandafter{\gobbletodot#1.}$%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{#1}{\expandafter\delbefdot\expandafter{\gobbletodot#1}}%
}%
\@ifdefinable\rfxx{%
\DeclareRobustCommand\rfxx[1]{%
\IfRefUndefinedBabel{#1}{\refused{#1}\nfss@text{\reset@font\bfseries??}}%
{%
\@ifundefined{hyperref}{\@firstofone}{\hyperref[{#1}]}%
{%
(\expandafter\expandafter\expandafter\delbefdot
\expandafter\expandafter\expandafter{\getrefbykeydefault{#1}{}{??}})%
}%
}%
}%
}%
\@ifdefinable\rnxx{%
\DeclareRobustCommand\rnxx[1]{%
\IfRefUndefinedBabel{#1}{\refused{#1}\nfss@text{\reset@font\bfseries??}}%
{%
\@ifundefined{hyperref}{\@firstofone}{\hyperref[{#1}]}%
{%
\expandafter\expandafter\expandafter\delbefdot
\expandafter\expandafter\expandafter{\getrefbykeydefault{#1}{}{??}}%
}%
}%
}%
}%
\makeatother
\newcommand{\rfstrip}[2]{(\rn{#1}--\rnx{#2})} % (3.1--2)
\newcommand{\rnstrip}[2]{\rn{#1}--\rnx{#2}} % 3.1--2
\newcommand{\rfdoublestrip}[2]{(\rn{#1}--\rnxx{#2})} % (3.1a--b)
\newcommand{\rndoublestrip}[2]{\rn{#1}--\rnxx{#2}} % 3.1a--b
\begin{document}
% Philex Label Formatting
\phildashes{}{.}
\subformat{a}{}{.}
\subsubformat{i}{(}{)}
\lb{main1}{This is main1.
\lba{sub11}{This is sub11.
\lba{subsub111}{This is subsub111.}
\lbz{subsub112}{This is subsub112.}}
\lbz{sub12}{This is sub12.
\lba{subsub121}{This is subsub121.}
\lbz{subsub122}{This is subsub122.}}}
\lb{main2}{This is main2.}
\textbackslash crefrange\{sub11\}\{sub12\} \textrightarrow{} \crefrange{sub11}{sub12} This works (no roman numbering).
\textbackslash crefrange\{subsub111\}\{subsub112\} \textrightarrow{} This will NOT compile fine (roman).
\textbackslash rnstrip\{sub11\}\{sub12\} \textrightarrow{} \rnstrip{sub11}{sub12} This works, because \textbackslash rnx doesn't work on the base of stripping to a delimiter.
\textbackslash rndoublestrip\{subsub111\}\{subsub112\} \textrightarrow{} \rndoublestrip{subsub111}{subsub112} Works, thanks to the dot.
\vspace{3ex}
\textbf{Now I change label formatting.}
\phildashes{.}{}
\subformat{1}{}{.}
\subsubformat{a}{}{.}
\lb{main3}{This is main3.
\lba{sub31}{This is sub31.
\lba{subsub311}{This is subsub311.}
\lbz{subsub312}{This is subsub312.}}
\lbz{sub32}{This is sub32.}}
\textbackslash rnstrip\{sub31\}\{sub32\} \textrightarrow{} \rnstrip{sub31}{sub32} This works fine, thanks to the dot.
\textbackslash rndoublestrip\{subsub311\}\{subsub312\} \textrightarrow{} \rndoublestrip{subsub311}{subsub312} Cannot work (no delim.)
\textbackslash crefrange\{sub31\}\{sub32\} \textrightarrow{} \crefrange{sub31}{sub32} This works fine (no roman).
\textbackslash crefrange\{subsub311\}\{subsub312\} \textrightarrow{} \crefrange{subsub311}{subsub312} This works fine (no roman).
\end{document}