
Когда я использую знак фунта/знак числа/знак решетки #
внутри команд и окружений, это относится к аргументам. Однако, не должно быть \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-}}
поэтому заменяющий текст \foo
is \def\baz#1{-#1-}
и вызов \foo
will определяются \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