Ситуация

Ситуация

Когда я использую знак фунта/знак числа/знак решетки #внутри команд и окружений, это относится к аргументам. Однако, не должно быть \detokenize{#}такНЕТАргумент?

Ситуация

Знак решетки отлично подходит в качестве разделителя в файлах журналов.

Пример

Попробуйте раскомментировать второй, \detokenizeчтобы получить ошибку.

\documentclass{article}
\usepackage{fontspec}% compile with xelatex
\newenvironment{detokenizetest}[1]
{% firstoftwo
 \detokenize{##############################################################################}%
 %\detokenize{##BEGIN#######################################################################}% uncommenting this causes a compile error
}%
{% secondoftwo
}%
\begin{document}
\null
\end{document}

Ошибка вывода

Эта ошибка возникает только при раскомментировании строки, содержащей BEGIN.

! Illegal parameter number in definition of \detokenizetest.
<to be read again>
                   }
l.9 }
     %
?

решение1

Поскольку #код категории равен 6, в TeX он имеет особое значение, поскольку используется для обозначения параметров в определениях макросов.

Правила TeX говорят, что когда вы хотитемагазинa #в заменяемом тексте макроса, его необходимо удвоить.

При обработке текста замены для определения макроса за синглом #должна следовать цифра (от 1 до 9), обозначающая указатель на соответствующий аргумент, тогда как ##будет сохранен как #. Это трюк, который позволяет сделать что-то вроде

\def\foo{\def\baz##1{-##1-}}

поэтому заменяющий текст \foois \def\baz#1{-#1-}и вызов \foowill определяются \bazкак макрос с одним аргументом.

Примитив \detokenizeв заменяющем тексте выполнит свою работукогда макрос вызывается и расширяется, а не во время определения, если только определение не выполнено с помощью \edef, который сначала выполнит полное расширение перед сохранением заменяющего текста в памяти.

Обратите внимание, что когда вы это сделаете \meaning\foo(исходя из приведенного выше определения), вам будет представлено

macro:->\def \baz ##1{-##1-}

и то же самое произойдет с \detokenizeтем, что использует тот же механизм. Таким образом, что-то вроде

\edef\hashmarks{\detokenize{####}}

на самом деле увидит два #в тексте замены, но в конечном итоге их будет четыре. Стандартный механизм при обработке \edefсначала уменьшит количество вдвое #, а затем\detokenize удвоит их обратно. В частности, выне мочьтаким образом создадим нечетное число #.

Если вы хотите создать линии-разделители, гораздо лучше использовать косвенный метод, заранее составив необходимый список токенов, состоящий из #с кодом категории 12. В примере я использую три из них, просто потому, что это нечетное число.

\documentclass{article}

\begingroup\lccode`?=`# \lowercase{\endgroup
  \newcommand{\lineofhashsigns}{???}
}

\newenvironment{delimitedtext}
  {\par\lineofhashsigns\par}
  {\par\lineofhashsigns\par}

\begin{document}

\begin{delimitedtext}
abc
\end{delimitedtext}

\end{document}

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

Другое определение, \lineofhashsignsкоторое не требует изменения, \lowercase— это изменение кода категории:

\catcode`#=12
\newcommand{\lineofhashsigns}{###}
\catcode`#=6

Вы можете добавить любой токен в текст замены, при условии, что вы не хотите, чтобы макрос имел аргументы.

решение2

Примитив \detokenizeдействительно будет означать, что #не рассматривается как параметр, а как один при расширении. Помните, что при обычном назначении ( \newcommandв LaTeX, \defкак примитив TeX) никакого расширения не происходит. Здесь, \newenvironmentвыполняет точно такое же 'просто сохраните' токены, как \newcommand. Это означает, что у нас есть обычное правило TeX, что при создании макроса мы должны иметь соответствующие параметры для каждого #присутствующего или мы должны иметь #дублированные токены.

Поскольку \newenvironmentв конечном итоге это приводит к \def, мы можем сделать то, что вы хотите, используя \edef:

\edef\detokenizetest#1{%
 \detokenize{##############################################################################}%
 \detokenize{##BEGIN#######################################################################}%
}
\def\enddetokenizetest{}% As \newenvironment will do this
\show\detokenizetest

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