Проблема: манипуляция строками со ссылками внутри

Проблема: манипуляция строками со ссылками внутри

Я определил новую команду \openintro, которую я вызываю в каждой главе своей работы. Эта команда в основном создает предложение lettrine, как на изображении ниже (не беспокойтесь о стиле текста):

\openintro{This is a working test}

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

Я использую некоторые команды xstringпакета для вырезания/разделения текста, чтобы соответствовать желаемому эффекту с lettrine. Однако я получаю некоторые ошибки при использовании \ref{label}внутри команды.

\openintro{This is a NOT working test due to~\ref{mylabel}}

Проблема связана с hyperrefпакетом, со ссылками, включенными. Команда \StrBeforeвыдает некоторые ошибки при столкновении со ссылкой в ​​строке. Если я отключаю hyperref, то при использовании проблем не возникает \ref. Но мне нужно использовать hyperref. Есть ли у вас какие-либо предложения по решению этой проблемы? Спасибо.

МВЭ:

\documentclass[12pt]{book}

\usepackage{xstring,lettrine}

\usepackage[pagebackref]{hyperref}
\hypersetup{
  linktoc=all,
  colorlinks=true,
  allcolors=red
}%

\newcommand{\openintro}[1]{%
  \def\firsttwowords{}%
  \def\firstword{}%
  \def\firstwordsplit{}%
  \def\secondword{}%
  \def\firstletter{}%
  \def\remainingtext{}%
  \def\charcount{}%
  \StrBefore[2]{#1}{ }[\firsttwowords]% get the first two words
  \StrBefore[1]{\firsttwowords}{ }[\firstword]% get the first word
  \StrGobbleLeft{\firstword}{1}[\firstwordsplit]% del the first letter of first word
  \StrBehind[1]{\firsttwowords}{ }[\secondword]% get only the second word
  \StrLeft{#1}{1}[\firstletter]% get the first letter of first word
  \StrLen{\firsttwowords}[\charcount]% count the number of characters of first two words
  \StrGobbleLeft{#1}{\charcount}[\remainingtext]% del the number of characters on the left of the whole sentence
  \lettrine{\firstletter}{\firstwordsplit~\secondword}~\textit{\remainingtext}\\[1PC]%
}%

\begin{document}

\chapter{test}

\openintro{This is a NOT working test due to~\ref{mylabel}}

\section{Hi there}\label{mylabel}

\end{document}

И ошибка:

! Use of \@xs@StrBefore@@ doesn't match its definition.
\@ifnextchar ... \reserved@d =#1\def \reserved@a {
                                                  #2}\def \reserved@b {#3}\f...
l.36 ...s a NOT working test due to~\ref{mylabel}}

! Argument of \@firstoftwo has an extra }.
<inserted text> 
                \par 
l.36 ...s a NOT working test due to~\ref{mylabel}}

Runaway argument?
! Paragraph ended before \@firstoftwo was complete.

решение1

Расширение \ref...приводит к ошибке. Однако xstringзнает \noexpandargмакрос, предотвращая расширение аргумента основной входной строки в xstringмакросы, но после первой операции расширение необходимо включить снова, используя \expandarg.

\documentclass[12pt]{book}

\usepackage{xstring,lettrine}

\usepackage[pagebackref]{hyperref}
\hypersetup{
  linktoc=all,
  colorlinks=true,
  allcolors=red
}%

\newcommand{\openintro}[1]{%
  \def\firsttwowords{}%
  \def\firstword{}%
  \def\firstwordsplit{}%
  \def\secondword{}%
  \def\firstletter{}%
  \def\remainingtext{}%
  \def\charcount{}%
  \noexpandarg%
  \StrBefore[2]{#1}{ }[\firsttwowords]% get the first two words
  \expandarg% Now expand again
  \StrBefore[1]{\firsttwowords}{ }[\firstword]% get the first word
  \StrGobbleLeft{\firstword}{1}[\firstwordsplit]% del the first letter of first word
  \StrBehind[1]{\firsttwowords}{ }[\secondword]% get only the second word
  \StrLeft{#1}{1}[\firstletter]% get the first letter of first word
  \StrLen{\firsttwowords}[\charcount]% count the number of characters of first two words
  \StrGobbleLeft{#1}{\charcount}[\remainingtext]% del the number of characters on the left of the whole sentence
  \lettrine{\firstletter}{\firstwordsplit~\secondword}~\textit{\remainingtext}\\[1PC]%
}%

\begin{document}

\chapter{test}

\openintro{This is a NOT working test due to~\ref{mylabel}}

\section{Hi there}\label{mylabel}

\end{document}

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

решение2

Мне кажется, что это слишком сложно. Зачем там \StrBeforeобработка и т.д.? Зачем вам нужен letrineпакет? Вы можете сделать то же самое следующим образом:

\documentclass[12pt]{book}
\usepackage[pagebackref]{hyperref}
\hypersetup{
  linktoc=all, 
  colorlinks=true,
  allcolors=red
}%

\def\openintro#1{\openintroA #1 \end}
\def\openintroA#1#2 #3 #4\end{\par
   \setbox0=\hbox{\fontsize{27}{27}\selectfont#1\/}%
   \hangindent=\wd0 \advance\hangindent by0pt \hangafter=-2
   \noindent \hskip-\hangindent\vbox to0pt{\kern-6pt\box0\vss}%
   {\uppercase{#2 #3} \it#4\unskip}%
   \medskip
}

\begin{document}

\chapter{test}

\openintro{This is a working test due to~\ref{mylabel}}

\section{Hi there}\label{mylabel}

\end{document}

Многие проблемы возникают из-за того, что люди не знают, что все можно сделать проще.

Редактировать: Из-за комментария Дэвида я изменил \openitroAопределение, чтобы поведение было похоже на использование letrine для текстов с большим количеством строк.

решение3

Я отвечаю на свой собственный вопрос, используя часть кода, предоставленного @wipet и lettrine (так как так легче манипулировать стилем текста). Вместо того, чтобы использовать всю манипуляцию строкой моего первого вопроса, я просто использую следующий код (который заменяет весь \newcommand{\openintro}):

\def\openintro#1{\openintroA #1 \end}
\def\openintroA#1#2 #3 #4\end{%
      \lettrine{#1}{#2~#3}~\textit{#4}%
}

Еще раз хочу поблагодарить @ChristianHupfer, @wipet и @DavidCarlisle за помощь.

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