Двойное двоеточие в метке prettyref

Двойное двоеточие в метке prettyref

Theprettyrefпакет работает, проверяя метки формы \label{format:name}и создавая ссылку, основанную только на format:. В документации говорится:

Не используйте этот символ :нигде в пределах метки, за исключением разделения формата от имени.

К сожалению, у меня есть случай использования, когда файл .tex генерируется автоматически с метками из трех частей \label{first:second:name}. MWE ниже. Реализация prettyrefна удивление проста, поэтому мне интересно, можно ли ее настроить так, чтобы она допускала метки из трех частей.

\documentclass[a4paper]{article}

\usepackage{graphicx}
\usepackage{prettyref}

\newrefformat{diag:cla}{Class Diagram \ref{#1}}
\newrefformat{diag:seq}{Sequence Diagram \ref{#1}}

\begin{document}
Behold: \prettyref{diag:seq:FirstExportedDiagram}.

\begin{figure}[h]
    \includegraphics[scale=0.5]{sequencediagram1.pdf}
    \caption{The first sequence diagram.}
    \label{diag:seq:FirstExportedDiagram}
\end{figure}

\end{document}

Редактировать:Для полноты картины я должен добавить, что ятакжевсе еще хотим сохранить возможность использовать старые метки с одним двоеточием. Автоматически экспортируемый файл .tex на самом деле имеет оба (например \label{datatype:integer}, , который будет отформатирован с помощью \newrefformat{datatype}{\textit{\ref{#1}}}, например). Я не говорю, что текущие ответы не соответствуют этому, но это полезно знать будущим читателям.

Я также должен упомянуть, что как писатель я в значительной степени полагаюсь на автодополнение, чтобы использовать эти экспортированные метки (их много, и они длинные). Это следует иметь в виду для определенных хаков формата.

решение1

Theруководство по пакету prettyrefговорит:

11\def\prettyref#1{\@prettyref#1:}

\@prettyrefВнутренний макрос \@prettyrefвыполняет всю работу. Он принимает два аргумента, разделенных :. Первый аргумент — имя формата. Если формат не определен, выдается предупреждение и \refиспользуется. В противном случае ссылка форматируется. \@prettyrefиспользует макросы LaTeX \refи \pagerefдля доступа к \newlabelструктуре данных. Надеюсь, это делает пакет достаточно надежным для использования с различными другими пакетами.

12 \def\@prettyref#1:#2:{%
13 \expandafter\ifx\csname pr@#1\endcsname\relax%
14 \PackageWarning{prettyref}{Reference format #1\space undefined}%
15 \ref{#1:#2}%
16 \else%
17 \csname pr@#1\endcsname{#1:#2}%
18 \fi%
19}

Поэтому \prettyrefвнутренне использует два :аргумента с разделителями для разделения той части аргумента, которая обозначает форматирование.
LaTeX удаляет фигурные скобки, окружающие весь аргумент.
Он также делает это с аргументами с разделителями.
Таким образом, фигурные скобки, окружающие весь аргумент с разделителями, могут использоваться для сокрытия экземпляров разделителя, встречающихся внутри аргумента с разделителями, так что механизм TeX для захвата аргумента с разделителями не будет применяться к этим экземплярам разделителя.

Это подразумевает:
Вместо \prettyref{Formatting:RemainderOfLabelName}вы можете сделать или или .
\prettyref{{Formatting}:RemainderOfLabelName}
\prettyref{Formatting:{RemainderOfLabelName}}
\prettyref{{Formatting}:{RemainderOfLabelName}}

Таким образом, в вашем случае для сокрытия :от механизма TeX по захвату :аргументов, разделенных -,/для того, чтобы все работало, просто заключите всю эту часть \prettyrefаргумента в фигурные скобки, которые обозначают форматирование, т. е. вместо
\prettyref{diag:seq:FirstExportedDiagram}
do
\prettyref{{diag:seq}:FirstExportedDiagram}
или
\prettyref{{diag:seq}:{FirstExportedDiagram}}.

МВЭ

\documentclass[a4paper]{article}

\usepackage{graphicx}
\usepackage{prettyref}

\newrefformat{diag:cla}{Class Diagram \ref{#1}}
\newrefformat{diag:seq}{Sequence Diagram \ref{#1}}

\begin{document}
Behold: \prettyref{{diag:seq}:FirstExportedDiagram}.

\begin{figure}[h]
    %\includegraphics[scale=0.5]{sequencediagram1.pdf}
    \includegraphics[scale=0.5]{example-image.pdf}
    \caption{The first sequence diagram.}
    \label{diag:seq:FirstExportedDiagram}
\end{figure}

\end{document}

урожайность:

введите описание изображения здесь

Объяснение:

\prettyref{{diag:seq}:FirstExportedDiagram}дает:
\@prettyref{diag:seq}:FirstExportedDiagram:, что в свою очередь дает:

  \expandafter\ifx\csname pr@diag:seq\endcsname\relax
    \PackageWarning{prettyref}{Reference format diag:seq\space undefined}%`
    \ref{diag:seq:FirstExportedDiagram}%`
  \else
    \csname pr@diag:seq\endcsname{diag:seq:FirstExportedDiagram}%`
  \fi

Так что, похоже, вам на самом деле не нужно ничего переопределять. С \prettyrefаргументом просто используйте дополнительные фигурные скобки здесь и там для сокрытия экземпляров от :механизма TeX для захвата :аргументов, разделенных -.



Если вы не хотите вручную вставлять фигурные скобки в автоматически сгенерированный код, а наличие более одного двоеточия, не вложенного в фигурные скобки, всегда означает, что только/именно первые два :разделенных символом -компонента представляют спецификацию форматирования, то вы можете сделать что-то вроде этого, что разбивает код по двоеточиям, не вложенным в фигурные скобки, и не удаляет/не убирает фигурные скобки:

\documentclass[a4paper]{article}
\usepackage{prettyref}
\usepackage{hyperref}

\makeatletter
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
\newcommand\UD@firstofone[1]{#1}%
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
%%=============================================================================
%% 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 first inner undelimited argument:
%%
%%   \UD@ExtractFirstArg{ABCDE} yields  {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields  {AB}
%%
%% Due to \romannumeral-expansion the result is delivered after two 
%% expansion-steps/after "hitting" \UD@ExtractFirstArg with \expandafter
%% twice.
%%
%% \UD@ExtractFirstArg's argument must not be blank.
%% This case can be cranked out via \UD@CheckWhetherBlank before calling
%% \UD@ExtractFirstArg.
%%
%% Use frozen-\relax as delimiter for speeding things up.
%% 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.
%%
%%.............................................................................
\@ifdefinable\UD@RemoveTillFrozenrelax{%
  \expandafter\expandafter\expandafter\UD@Exchange
  \expandafter\expandafter\expandafter{%
  \expandafter\expandafter\ifnum0=0\fi}%
  {\long\def\UD@RemoveTillFrozenrelax#1#2}{{#1}}%
}%
\expandafter\UD@PassFirstToSecond\expandafter{%
  \romannumeral\expandafter
  \UD@PassFirstToSecond\expandafter{\romannumeral
    \expandafter\expandafter\expandafter\UD@Exchange
    \expandafter\expandafter\expandafter{%
    \expandafter\expandafter\ifnum0=0\fi}{\UD@stopromannumeral#1}%
  }{%
    \UD@stopromannumeral\romannumeral\UD@ExtractFirstArgLoop
  }%
}{%
  \newcommand\UD@ExtractFirstArg[1]%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
  {\UD@stopromannumeral#1}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}}%
}%
\@ifdefinable\UD@GobbleToColon{\long\def\UD@GobbleToColon#1:{}}%
\@ifdefinable\UD@KeepToColon{\long\def\UD@KeepToColon#1:{{#1}}}%
\newcommand\UD@SplitColon[4]{%
  % #1 Tokens to prepend to {<Already splitted stuff>{<stuff splitted in this iteration>}}{<New remainder to split>}
  %    if <Remainder to split> does contain colon.
  % #2 Tokens to prepend to <Already splitted stuff>{<Remainder to split>} 
  %    if <Remainder to split> does not contain colon.
  % #3 Already splitted stuff.
  % #4 Remainder to split.
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToColon#4:}%
  {#2#3{#4}}{%
    \expandafter\UD@PassFirstToSecond\expandafter{\UD@GobbleToColon#4}{%
      \expandafter\UD@PassFirstToSecond\expandafter{%
        \romannumeral
        \expandafter\UD@Exchange\expandafter{%
          \romannumeral
          \expandafter\expandafter\expandafter\expandafter
          \expandafter\expandafter\expandafter
          \UD@stopromannumeral
          \expandafter\UD@ExtractFirstArg\expandafter{\UD@KeepToColon#4}%
        }{\UD@stopromannumeral#3}%
      }{#1}%
    }%
  }%
}%
\renewcommand\prettyref[1]{%
  \UD@SplitColon{%
    \UD@SplitColon{% Here you could nest more \UD@SplitColon.
      \expandafter\UD@prettyref@morethanonecolon\UD@firstofone
    }{%
      \UD@prettyref@onecolon
    }%
  }{%
    \PackageWarning{prettyref}{No referencing format specified}\ref
  }{}{#1}%
}%
\newcommand\UD@prettyref@onecolon[2]{%
  \expandafter\ifx\csname pr@#1\endcsname\relax
    \PackageWarning{prettyref}{Reference format #1\space undefined}%
    \ref{#1:#2}%
  \else
    \csname pr@#1\endcsname{#1:#2}%
  \fi
}%
\newcommand\UD@prettyref@morethanonecolon[3]{%
  \expandafter\ifx\csname pr@#1:#2\endcsname\relax
    \PackageWarning{prettyref}{Reference format #1:#2\space undefined}%
    \ref{#1:#2:#3}%
  \else
    \csname pr@#1:#2\endcsname{#1:#2:#3}%
  \fi
}%
\makeatother

% In order to create hyperlinks, you can use
%
% \hyperref[{<referencing label>}]{<textual phrase which shall be a hyperlink>}
%
% As components of <textual phrase which shall be a hyperlink> you can use starred
% referencing-commands \ref*/\pageref* which themselves don't produce hyperlinks.
% This avoids errors due to nesting hyperlinks within hyperlinks.

\newrefformat{diag}{\hyperref[{#1}]{Diagram \ref*{#1}}}
\newrefformat{diag:cla}{\hyperref[{#1}]{Class Diagram \ref*{#1}}}
\newrefformat{diag:seq}{\hyperref[{#1}]{Sequence Diagram \ref*{#1}}}

\newcounter{democounter}

\begin{document}

You should get: Sequence Diagram 1\par
You actually get: \prettyref{diag:seq:FirstExportedDiagram:x:Y}
\medskip

You should get:  Sequence Diagram 2\par
You actually get: \prettyref{diag:seq:FirstExportedDiagram}
\medskip

You should get: Class Diagram 3\par
You actually get: \prettyref{diag:cla:FirstExportedDiagram}
\medskip

You should get: Diagram 4\par
You actually get: \prettyref{diag:FirstExportedDiagram}
\medskip

% You should get: 5 plus a warning "No referencing format specified" \par
% You actually get: \prettyref{FirstExportedDiagram}
% \medskip

You should get: 5\par
You actually get: \ref{FirstExportedDiagram}.
\medskip


Here the democounter is stepped. It has the value \refstepcounter{democounter}\thedemocounter.
\label{diag:seq:FirstExportedDiagram:x:Y}%
\bigskip

Here the democounter is stepped. It has the value \refstepcounter{democounter}\thedemocounter.
\label{diag:seq:FirstExportedDiagram}%
\bigskip

Here the democounter is stepped. It has the value \refstepcounter{democounter}\thedemocounter.
\label{diag:cla:FirstExportedDiagram}%
\bigskip

Here the democounter is stepped. It has the value \refstepcounter{democounter}\thedemocounter.
\label{diag:FirstExportedDiagram}%
\bigskip

Here the democounter is stepped. It has the value \refstepcounter{democounter}\thedemocounter.
\label{FirstExportedDiagram}%
\bigskip

\end{document}

введите описание изображения здесь

решение2

Не совсем понятно, почему prettyref разделяет конец двоеточием. Обычный разделитель здесь \@nil:

\documentclass[a4paper]{article}

\usepackage{graphicx}
\usepackage{prettyref}

\newrefformat{diag:cla}{Class Diagram \ref{#1}}
\newrefformat{diag:seq}{Sequence Diagram \ref{#1}}
\makeatletter
\def\prettyref#1{\@prettyref#1\@nil}
\def\@prettyref#1:#2\@nil{%  
  \expandafter\ifx\csname pr@#1\endcsname\relax%
    \PackageWarning{prettyref}{Reference format #1\space undefined}%
    \ref{#1:#2}%
  \else%
    \csname pr@#1\endcsname{#1:#2}%
  \fi%
}
\makeatother
\begin{document}
Behold: \prettyref{diag:seq:FirstExportedDiagram}.

\begin{figure}[h]
    \includegraphics[scale=0.5]{example-image.pdf}
    \caption{The first sequence diagram.}
    \label{diag:seq:FirstExportedDiagram}
\end{figure}
\end{document}

Связанный контент