2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу 1, 2, 3  След.
 
 Как обойти \detokenize?
Сообщение21.06.2022, 20:57 
Аватара пользователя
Предыстория вопроса:

Я решил сделать в файле pdf всплывающие подсказки с текстом сносок. Типа, наводишь мышь на символ сноски и появляется окошко с текстом сноски. Гораздо удобнее, чем скакать каждый раз вниз страницы по ссылке, которую предлагает пакет hyperref. Поскольку я убедился, что существующие пакеты - типа cooltooltip - делают это весьма криво (как минимум, они пытаются встроить в pdf JavaScript, каковой многие ридеры отказываются исполнять по соображениям безопасности), я провёл некоторое собственное исследование, покопавшись в PDF reference и в мануале к pdfTeX, которым я пользуюсь для компиляции TeX-овских исходников. В итоге я пришёл к выводу, что более или менее нормально на роль всплывающих подсказок подходят только т.н. "аннотации" типа /Text (вообще-то в pdf предусмотрена куча разных типов аннотаций, но всё остальное - не то).

Неприятность заключается в том, что выводимый в аннотацию текст должен иметь кодировку UTF-16 big endian, ничего иного формат pdf для отображения в этом месте русских букв не предлагает. Я нашёл пакет stringenc, который предлагает средства перекодировки текста. В итоге вот такой код:
Используется синтаксис LaTeX
\usepackage{stringenc}
...
\StringEncodingConvert\myfootip{\detokenize{#1}}{utf8}{utf16be}%
...

делает из исходной кодировки моего текста UTF-8 то, что мне нужно. А именно, на основе текста, переданного макросу в параметре #1, создаётся команда \myfootip, которую я могу поставить в команду, генерирующую pdf-аннотацию типа /Text со вполне читаемым русским содержанием. Сначала я не понял, зачем нужна команда \detokenize{} внутри макроса и пытался выполнять перекодировку без неё. Но в результате на выходе макроса перекодировки получается (и, соответственно, отображается в тексте аннотации) вместо русских букв всякая ерунда типа \T2A\CYRP или \T2A\cyro. Почитав документацию к пакету stringenc, я осознал, что pdfTeX воспринимает каждую русскую букву как токен (таков механизм русификации в латех), а эти коды - результат "раскрытия" этих токенов. Там я и нашёл подсказку про то, что нужно использовать \detokenize{}. После этого всё стало замечательно работать.

Но (и тут от предыстории мы переходим собственно к сути вопроса) у меня в сносках полно ссылок на литературу! Типа: "Подробнее об этом можно почитать в [1]". В исходном тексте сноски, который я передаю макросу на перекодировку, ссылку на библиографию в виде \cite{source_name} или чего-то подобного передавать бесполезно, потому что \detokenize{} препятствует раскрытию этого кода и на выходе мы получим ерунду. Можно везде по тексту руками заменить эти коды на [1] и т.п., но это очень кривое решение, потому что в библиографию может что-то вставиться и вся нумерация источников съедет.

Вопрос заключается в том, как обойти этот \detokenize{} для ссылок на библиографию (так, чтобы TeX нормально сгенерировал номер источника), но при этом сохранить его эффект воздействия на русские буквы?

 
 
 
 Re: Как обойти \detokenize?
Сообщение22.06.2022, 12:52 
Может быть, проще набирать исходный файл в UTF-16, или перекодировать непосредственно перед компиляцией?

-- 22.06.2022, 13:58 --

Покажите компилирующийся пример, я попробую с ним поиграть, может быть.

 
 
 
 Re: Как обойти \detokenize?
Сообщение22.06.2022, 18:12 
Аватара пользователя
Slav-27 в сообщении #1558185 писал(а):
Может быть, проще набирать исходный файл в UTF-16, или перекодировать непосредственно перед компиляцией?
Не хочется прогибаться под изменчивый мир. UTF-16 - это что-то специфически виндузовское, к моей рабочей среде отношения не имеющее.

Slav-27 в сообщении #1558185 писал(а):
Покажите компилирующийся пример, я попробую с ним поиграть, может быть.

код: [ скачать ] [ спрятать ]
Используется синтаксис LaTeX
\documentclass[
    a4paper,% размеры листа
    11pt,% размеры нормального шрифта
    toc=bibliography% включить в оглавление литературу
    ]{scrbook} % книга KOMAscript, см. scrguien.pdf

\usepackage[T2A]{fontenc}% Выбор внутренней TeX−кодировки
\usepackage[utf8]{inputenc}% Выбор кодовой страницы документа.
\usepackage[english,russian]{babel}% Выбор языка документа.
\usepackage{indentfirst}% Начинать первый параграф с красной строки.
\usepackage{xcolor}% Для работы с цветами, включая гиперссылки
\usepackage{stringenc}% Конвертер кодировок, позволяет из utf8 делать utf16be
\usepackage[hyperfootnotes=false,pagebackref=true,pdftex]{hyperref}% Для гиперссылок, включая из оглавления, на библиографию и обратные
\hypersetup{
    colorlinks=true% ссылки будут выделяться цветом, а не рамкой
}

\title{Пробный заголовок}
\subtitle{пробной книги}
\author{epros}
\date{\today}

% Макрос создаёт сноску с всплывающей подсказкой (первый аргумент); второй агрумент - содержимое нормальной сноски внизу страницы
\newcommand*{\myfootnote}[2]{%
 \StringEncodingConvert\myfootip{\detokenize{#1}}{utf8}{utf16be}%
 \pdfstartlink user{%
  /Subtype /Text% создаётся аннотация типа Text
  /T (epros)% автор аннотации
  /Contents (\string\376\string\377\myfootip)% текст аннотации; префикс перед \myfootip согласно формату pdf идентифициует строку unicode
  /AP <<
   /N \emptyicon\space 0 R% ссылка на создаваемый в начале документа объект pdf - основной вид значка аннотации
   /R \emptyicon\space 0 R% вид значка при наведённом указателе мыши
   /D \emptyicon\space 0 R% вид значка при нажатой кнопке мыши
  >>
 }\footnote{#2}\pdfendlink%
}%

\begin{document}
   
    \maketitle
   
        \tableofcontents
       
        % Этот код создаёт объект pdf - пустой бокс для использования вместо стандартного значка текстовой аннотации
        \newbox\tempboxa
        \setbox\tempboxa=\hbox{}
        \immediate\pdfxform\tempboxa
        \edef\emptyicon{\the\pdflastxform}% сохраняем номер объекта для использования при вызове макроса \myfootnote
 
        \part{Пробная часть}
        \chapter{Пробная глава}
        \section{Пробный раздел}
    Что же позволяет говорить не просто об эквивалентности, а о равенстве объектов? Для этого они должны быть ещё и неразличимы. Принцип, отождествляющий неразличимость и равенство объектов, известен как <<закон Лейбница>>\myfootnote{См. переписку Лейбница с Кларком в [1].}{См. переписку Лейбница с Кларком в~\cite{leibniz_tom1}.}.

{\raggedright
\begin{thebibliography}{99}
       
        \bibitem{leibniz_tom1}Г.\,В.~Лейбниц. Сочинения в четырёх томах (под редакцией В.\,В.~Соколова, 1982). Том 1. Упоминается на с.\!\!
       

\end{thebibliography}
}
   
\end{document}
 


Компилировать нужно с помощью pdfTeX.

Если убрать из макроса \detokenize, то коды TA2 вместо русских букв появляются уже в строке \myfootip. Я проверял с помощью \write16{\myfootip}, т.е. это не эффект генерации pdf, а результат работы непосредственно макроса \StringEncodingConvert.

 
 
 
 Re: Как обойти \detokenize?
Сообщение23.06.2022, 15:43 
Аватара пользователя
Я также попробовал на тестовом примере последовать и вот этому совету:

Slav-27 в сообщении #1558185 писал(а):
Может быть, проще набирать исходный файл в UTF-16, или перекодировать непосредственно перед компиляцией?

Сразу хочу заметить, что это оказалось не проще.
Во-первых, мой комп оказался little endian, так что текстовые редакторы (в основном я пользуюсь Kate) понимать UTF-16BE отказались. К счастью, оказалось, что ридеры PDF нормально воспринимают и текст формата UTF-16LE, нужно только в начале текстовой строки ставить \377\376 вместо \376\377.
Во-вторых, у текстовых редакторов оказалась настройка "кодировки по умолчанию", которая, конечно, стоит на UTF-8 и менять её - значит создавать неудобства при работе с другими файлами. Почему-то кодировку UTF-16LE они по умолчанию распознавать не хотят, так что приходится при каждом открытии файла им указывать кодировку явно.
В третьих, мой pdfTeX почему-то ждёт на входе файл именно в кодировке UTF-8. Вот что я вижу в логе:
Код:
! LaTeX Error: Invalid UTF-8 byte "FF.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
...                                             
                                                 
l.1 �
     �\^^@U^^@s^^@e^^@R^^@a^^@w^^@I^^@n^^@p^^@u^^@t^^@E^^@n^^@c^^@o^^@d^^@i^...

The document does not appear to be in UTF-8 encoding.
Try adding \UseRawInputEncoding as the first line of the file
or specify an encoding such as \usepackage [latin1]{inputenc}
in the document preamble.
Alternatively, save the file in UTF-8 using your editor or another tool

Попытка, как советуют, указать в первой сроке \UseRawInputEncoding, а также указать \usepackage[utf16]{inputenc} (вместо \usepackage[utf8]{inputenc}) ничего не изменила.

Пока мне так и не удалось решить эту проблему. Почему-то не нахожу в документации на pdfTeX, где ему можно указать, что кодировка исходного файла - UTF-16LE.

-- Чт июн 23, 2022 17:40:13 --

Ха, ответ (на вопрос о возможности использования исходного файла в кодировке UTF-16) здесь. Как видите, он отрицательный. В мануал на пакет inputenc я тоже заглянул, там в списке допустимых кодировок никаких UTF-16 не значится. Стало быть, такой вариант отпадает.

 
 
 
 Re: Как обойти \detokenize?
Сообщение24.06.2022, 15:43 
Аватара пользователя
Похоже, что такие макросы (я имею в виду перекодировщик) пишутся для использования исключительно гуру чистого TeX. Во всяком случае, до моего понимания столь тонкие нюансы работы TeX пока не доходят. Вот, простая задача: Хочу перекодировать в UTF-16 имя автора, которое находится в переменной \@author. И не могу! потому что такой вариант:
Используется синтаксис LaTeX
\StringEncodingConvert\recoded{\@author}{utf8}{utf16le}

раскрывает каждую русскую букву имени автора в T2A коды, а такой вариант:
Используется синтаксис LaTeX
\StringEncodingConvert\recoded{\detokenize{\@author}}{utf8}{utf16le}

вместо имени автора выводит имя команды \@author.

Получается, что переменную, содержащую имя автора, я использовать никак не могу и мне придётся здесь вбивать имя автора вручную. А это значит, что нужно помнить, где что вбито.

-- Пт июн 24, 2022 17:09:50 --

Очевидно, нужно обладать какими-то глубинными познаниями о том, когда и каким образом какие именно макросы раскрывает TeX. Например, можно непосредственно передать в сгенерированный объект PDF (в ту же аннотацию) код ссылки на библиографию - \cite{source_name}, но при этом этот код не будет раскрыт, т.е. в файле PDF окажется именно код, а не номер источника. При этом можно определить промежуточную переменную, содержащую эту ссылку:
Используется синтаксис LaTeX
\def\reference_on_this_source{\cite{source_name}}

но попытка её передачи в объект PDF тоже приведёт к передаче только кода, а не результата его выполнения. Вы скажете, что для этих случаев есть \edef, который должен раскрывать все макросы в момент его вызова. Но если определить переменную вот так:
Используется синтаксис LaTeX
\edef\reference_on_this_source{\cite{source_name}}

а потом попытаться её передать в объект PDF, то возникает ошибка. Оно и понятно, код ссылки на библиографию, очевидно, может быть раскрыт только после того, как TeX сформирует библиографию, т.е. ему станет известен номер этого источника. Но мне-то как определить этот момент? Я могу подать команду на формирование объекта PDF и позже. Вот только когда?

 
 
 
 Re: Как обойти \detokenize?
Сообщение24.06.2022, 18:10 
Надо перед \detokenize делать \expandafter.

В общем, похоже, с этим Юникодом без извращений нельзя.
Я повозился, окончательно не сделал, но кое-что получилось, подробнее скорее всего напишу попозже, сейчас некогда просто.

Но вообще-то я совершенно не эксперт, может быть, имеет смысл спросить на tex.stackexchange.com или дождаться Red_Herring.

 
 
 
 Re: Как обойти \detokenize?
Сообщение24.06.2022, 20:37 
Аватара пользователя
Slav-27 в сообщении #1558386 писал(а):
Надо перед \detokenize делать \expandafter.

\expandafter как-то не так срабатывает. В PDF попадает имя переменной \@author вместо её значения, причём в исходной кодировке UTF-8.

Вообще, эти теховские правила формирования и раскрытия токенов - это явно не для средних умов. Вот я решил попробовать ещё один вариант перекодировки - с помощью вызова системной утилиты iconv. Правда для этого мне пришлось искать, как в конфигах texlive включить shell_escape, который по умолчанию ограничен коротким списком команд. Но теперь вот такой код выводит у меня нормальную строку:
Используется синтаксис LaTeX
\def\recodedtext#1{%
 \input{|echo "#1"|iconv -f UTF8 -t UTF8 /dev/stdin}%
}
...
\recodedtext{См. переписку Лейбница с Кларком в [1].}

Здесь выходной кодировкой я поставил тоже UTF-8, иначе получившиеся кракозябры tex не воспринимает. Но сути это не меняет - перекодировщик работает, при необходимости можно добавить параметр -o outfile.txt, который вместо используемого по умолчанию стандартного выхода указывает файл, и убедиться в том, что файл создаётся и с правильным содержимым. Но если я укажу этот \recodedtext в качестве параметра команды \write16 или параметра своего макроса, генерирующего аннотацию, то возникают ошибки. Почему?

 
 
 
 Re: Как обойти \detokenize?
Сообщение25.06.2022, 23:07 
Вот что получилось. Прямо с \cite не сработает, но дальше уже проще (?).
код: [ скачать ] [ спрятать ]
Используется синтаксис LaTeX
\documentclass[
    a4paper,% размеры листа
    11pt,% размеры нормального шрифта
    toc=bibliography% включить в оглавление литературу
    ]{book} % книга KOMAscript, см. scrguien.pdf (у меня нету такого документкласса)

\usepackage[T2A]{fontenc}% Выбор внутренней TeX−кодировки
\usepackage[utf8]{inputenc}% Выбор кодовой страницы документа.
\usepackage[english,russian]{babel}% Выбор языка документа.
\usepackage{indentfirst}% Начинать первый параграф с красной строки.
\usepackage{xcolor}% Для работы с цветами, включая гиперссылки
\usepackage{stringenc}% Конвертер кодировок, позволяет из utf8 делать utf16be
\usepackage[hyperfootnotes=false,pagebackref=true,pdftex]{hyperref}% Для гиперссылок, включая из оглавления, на библиографию и обратные
\hypersetup{
    colorlinks=true% ссылки будут выделяться цветом, а не рамкой
}


\def\makeother#1#2\relax{\ifx\relax#1\relax\else\catcode`#1=12\makeother#2\relax\relax\fi}% берёт последовательность токенов-символов, заканчивающуюся токеном "контрольная последовательность relax" (буква кириллицы -- 2 токена-символа), и меняет для таких символов правило назначения каткодов: им будет назначаться other
\def\azbuka{АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя}



\title{Пробный заголовок}
%\subtitle{пробной книги}
\author{epros}
\date{\today}


% Макрос создаёт сноску с всплывающей подсказкой (ВТОРОЙ аргумент); ПЕРВЫЙ агрумент - содержимое нормальной сноски внизу страницы
%
% Каждая буква кириллицы в UTF-8 кодируется 2 байтами. TeX читает каждый из этих 2 байтов как отдельный токен-символ с каткодом 13 (active). Я меняю каткоды символов, встречающихся в буквах кириллицы, на 12 (other), чтобы они не раскрывались (expand), когда мы будем раскрывать всё остальное.
% Каткоды замораживаются при передаче в качестве аргумента макроса (потому что каткод назначается при токенизации, которая происходит только один раз и до передачи аргумента макросу). Поэтому я вместо 1 макроса пишу 2, первый берёт в качестве аргумента текст нормальной сноски и далее меняет правила назначения каткодов, а второй потом забирает оставшийся аргумент -- текст всплывающей подсказки.
\def\myfootnote#1{%
\begingroup\expandafter\makeother\azbuka\relax\myfootnoteaux{#1}}
\def\myfootnoteaux#1#2{%
\edef\myfootipUTFeight{#2}% здесь происходит раскрытие контрольных последовательностей, содержащихся в тексте всплывающей подсказки
\StringEncodingConvert\myfootip{\myfootipUTFeight}{utf8}{utf16be}%
\pdfstartlink user{%
  /Subtype /Text% создаётся аннотация типа Text
  /T (epros)% автор аннотации
  /Contents (\string\376\string\377\myfootip)% текст аннотации; префикс перед \myfootip согласно формату pdf идентифициует строку unicode
  /AP <<
   /N \emptyicon\space 0 R% ссылка на создаваемый в начале документа объект pdf - основной вид значка аннотации
   /R \emptyicon\space 0 R% вид значка при наведённом указателе мыши
   /D \emptyicon\space 0 R% вид значка при нажатой кнопке мыши
  >>
}%
\footnote{#1}%
\pdfendlink%
\endgroup% изменённые правила назначения каткодов действуют досюда
}

\begin{document}
   
    \maketitle
   
   \tableofcontents
   
   % Этот код создаёт объект pdf - пустой бокс для использования вместо стандартного значка текстовой аннотации
   \newbox\tempboxa
   \setbox\tempboxa=\hbox{}
   \immediate\pdfxform\tempboxa
   \edef\emptyicon{\the\pdflastxform}% сохраняем номер объекта для использования при вызове макроса \myfootnote
 
   \part{Пробная часть}
   \chapter{Пробная глава}
   \section{Пробный раздел}

\def\mycs{kontrol'naya posledovatel'nost' raskrylas'}

    Что же позволяет говорить не просто об эквивалентности, а о равенстве объектов? Для этого они должны быть ещё и неразличимы. Принцип, отождествляющий неразличимость и равенство объектов, известен как <<закон Лейбница>>%
\myfootnote{См. переписку Лейбница с Кларком в \cite{leibniz_tom1}.}{См. переписку Лейбница с Кларком в \mycs.}.

{\raggedright
\begin{thebibliography}{99}
   
   \bibitem{leibniz_tom1}Г.\,В.~Лейбниц. Сочинения в четырёх томах (под редакцией В.\,В.~Соколова, 1982). Том 1. Упоминается на с.%\!\!

\end{thebibliography}
}
   
\end{document}


Наверно, можно менять каткоды непосредственно у токенов аргумента, но для этого придётся парсить аргумент.

 
 
 
 Re: Как обойти \detokenize?
Сообщение26.06.2022, 11:48 
epros в сообщении #1558402 писал(а):
\expandafter как-то не так срабатывает. В PDF попадает имя переменной \@author вместо её значения, причём в исходной кодировке UTF-8.
Используется синтаксис LaTeX
\def\myauthorUTFeight{Пушкин}
\StringEncodingConvert\myauthor{\expandafter\detokenize\expandafter{\myauthorUTFeight}}{utf8}{utf16be}

В выражении \detokenize{\myauthorUTFeight} между \detokenize и \myauthorUTFeight стоит токен {, поэтому надо 2 \expandafter. Первый \expandafter раскрывает второй \expandafter (не трогая \detokenize), который раскрывает \myauthorUTFeight, не трогая {.

 
 
 
 Re: Как обойти \detokenize?
Сообщение27.06.2022, 21:07 
Аватара пользователя
Slav-27 в сообщении #1558513 писал(а):
Используется синтаксис LaTeX
\def\myauthorUTFeight{Пушкин}
\StringEncodingConvert\myauthor{\expandafter\detokenize\expandafter{\myauthorUTFeight}}{utf8}{utf16be}

В выражении \detokenize{\myauthorUTFeight} между \detokenize и \myauthorUTFeight стоит токен {, поэтому надо 2 \expandafter. Первый \expandafter раскрывает второй \expandafter (не трогая \detokenize), который раскрывает \myauthorUTFeight, не трогая {.

Да, спасибо, это понятно.

-- Пн июн 27, 2022 22:47:31 --

Slav-27 в сообщении #1558491 писал(а):
код: [ скачать ] [ спрятать ]
Используется синтаксис LaTeX
\documentclass[
    a4paper,% размеры листа
    11pt,% размеры нормального шрифта
    toc=bibliography% включить в оглавление литературу
    ]{book} % книга KOMAscript, см. scrguien.pdf (у меня нету такого документкласса)

\usepackage[T2A]{fontenc}% Выбор внутренней TeX−кодировки
\usepackage[utf8]{inputenc}% Выбор кодовой страницы документа.
\usepackage[english,russian]{babel}% Выбор языка документа.
\usepackage{indentfirst}% Начинать первый параграф с красной строки.
\usepackage{xcolor}% Для работы с цветами, включая гиперссылки
\usepackage{stringenc}% Конвертер кодировок, позволяет из utf8 делать utf16be
\usepackage[hyperfootnotes=false,pagebackref=true,pdftex]{hyperref}% Для гиперссылок, включая из оглавления, на библиографию и обратные
\hypersetup{
    colorlinks=true% ссылки будут выделяться цветом, а не рамкой
}


\def\makeother#1#2\relax{\ifx\relax#1\relax\else\catcode`#1=12\makeother#2\relax\relax\fi}% берёт последовательность токенов-символов, заканчивающуюся токеном "контрольная последовательность relax" (буква кириллицы -- 2 токена-символа), и меняет для таких символов правило назначения каткодов: им будет назначаться other
\def\azbuka{АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя}



\title{Пробный заголовок}
%\subtitle{пробной книги}
\author{epros}
\date{\today}


% Макрос создаёт сноску с всплывающей подсказкой (ВТОРОЙ аргумент); ПЕРВЫЙ агрумент - содержимое нормальной сноски внизу страницы
%
% Каждая буква кириллицы в UTF-8 кодируется 2 байтами. TeX читает каждый из этих 2 байтов как отдельный токен-символ с каткодом 13 (active). Я меняю каткоды символов, встречающихся в буквах кириллицы, на 12 (other), чтобы они не раскрывались (expand), когда мы будем раскрывать всё остальное.
% Каткоды замораживаются при передаче в качестве аргумента макроса (потому что каткод назначается при токенизации, которая происходит только один раз и до передачи аргумента макросу). Поэтому я вместо 1 макроса пишу 2, первый берёт в качестве аргумента текст нормальной сноски и далее меняет правила назначения каткодов, а второй потом забирает оставшийся аргумент -- текст всплывающей подсказки.
\def\myfootnote#1{%
\begingroup\expandafter\makeother\azbuka\relax\myfootnoteaux{#1}}
\def\myfootnoteaux#1#2{%
\edef\myfootipUTFeight{#2}% здесь происходит раскрытие контрольных последовательностей, содержащихся в тексте всплывающей подсказки
\StringEncodingConvert\myfootip{\myfootipUTFeight}{utf8}{utf16be}%
\pdfstartlink user{%
  /Subtype /Text% создаётся аннотация типа Text
  /T (epros)% автор аннотации
  /Contents (\string\376\string\377\myfootip)% текст аннотации; префикс перед \myfootip согласно формату pdf идентифициует строку unicode
  /AP <<
   /N \emptyicon\space 0 R% ссылка на создаваемый в начале документа объект pdf - основной вид значка аннотации
   /R \emptyicon\space 0 R% вид значка при наведённом указателе мыши
   /D \emptyicon\space 0 R% вид значка при нажатой кнопке мыши
  >>
}%
\footnote{#1}%
\pdfendlink%
\endgroup% изменённые правила назначения каткодов действуют досюда
}

\begin{document}
   
    \maketitle
   
   \tableofcontents
   
   % Этот код создаёт объект pdf - пустой бокс для использования вместо стандартного значка текстовой аннотации
   \newbox\tempboxa
   \setbox\tempboxa=\hbox{}
   \immediate\pdfxform\tempboxa
   \edef\emptyicon{\the\pdflastxform}% сохраняем номер объекта для использования при вызове макроса \myfootnote
 
   \part{Пробная часть}
   \chapter{Пробная глава}
   \section{Пробный раздел}

\def\mycs{kontrol'naya posledovatel'nost' raskrylas'}

    Что же позволяет говорить не просто об эквивалентности, а о равенстве объектов? Для этого они должны быть ещё и неразличимы. Принцип, отождествляющий неразличимость и равенство объектов, известен как <<закон Лейбница>>%
\myfootnote{См. переписку Лейбница с Кларком в \cite{leibniz_tom1}.}{См. переписку Лейбница с Кларком в \mycs.}.

{\raggedright
\begin{thebibliography}{99}
   
   \bibitem{leibniz_tom1}Г.\,В.~Лейбниц. Сочинения в четырёх томах (под редакцией В.\,В.~Соколова, 1982). Том 1. Упоминается на с.%\!\!

\end{thebibliography}
}
   
\end{document}

Да, вижу, что \mycs в тексте аннотации раскрылся. Но в коде пока я многого не понял.
1) Я правильно понимаю, что использование \makeother внутри определения \makeother - это рекурсия? Так можно?
2) Я правильно понимаю, что \makeother#2\relax\relax раскрывается в то же самое, что стоит внутри фигурных скобок после \makeother#1#2\relax, только в аргументе на один байт в начале строки меньше? А зачем нужен последний \relax в обоих выражениях? Почитав описание синтаксиса \def, я так понял, что #1#2\relax в перечислении аргументов означает, что второй аргумент определяемого макроса должен заканчиваться на \relax. Вот только я не понял, как TeX, встретив этот макрос, определит, где первый аргумент, а где второй. У Вас там записано \makeother\azbuka\relax\myfootnoteaux{#1}. Это значит, что первый байт строки, в которую раскроется \azbuka, воспримется как первый аргумент, а остальная строка до \relax - как второй? Почему, например, не воспринять как второй аргумент второй байт строки и не выдать ошибку, потому что после него не обнаружен \relax?
3) И что такое \myfootnoteaux{#1}? Дальше, вроде, идёт нечто, похожее на его определение с двумя аргументами, но:
(а) разве может быть определение макроса позже первого вызова?
(б) в вызове этого макроса я не вижу двух аргументов; или второй аргумент - это закрывающая фигурная скобка? так можно?
(в) в определении этого макроса я вижу открывающую фигурную скобку, к которой не вижу парную закрывающую.
4) Я не понял использования \begingroup и \endgroup. Разве это не то же самое, что фигурные скобки? А если так, то разве следующая за \begingroup закрывающая фигурная скобка не должна закрыть группу?

 
 
 
 Re: Как обойти \detokenize?
Сообщение28.06.2022, 01:41 
epros (UPD: я сделал существенные исправления)
Стандартное место, где искать ответы на такие вопросы, -- The TeXBook, by Don Knuth. Я, как уже говорил, не эксперт: отвечаю в меру своего понимания, относитесь ко мне с недоверием.

1) Да. Да.

2) Да (кроме последней итерации).
The TeXBook, chapter 20 писал(а):
How does TeX determine where an argument stops, you ask. Answer: There are two cases. A delimited parameter is followed in the parameter text by one or more non-parameter tokens, before reaching the end of the parameter text or the next parameter token; in this case the corresponding argument is the shortest (possibly empty) sequence of tokens with properly nested {...} groups that is followed in the input by this particular list of non-parameter tokens. (Category codes and character codes must both match, and control sequence names must be the same.) An undelimited parameter is followed immediately in the parameter text by a parameter token, or it occurs at the very end of the parameter text; in this case the corresponding argument is the next nonblank token, unless that token is ‘ { ’, when the argument will be the entire {...} group that follows. In both cases, if the argument found in this way has the form ‘ { <nested tokens> } ’, where <nested tokens> stands for any sequence of tokens that is properly nested with respect to braces, the outermost braces enclosing the argument are removed and the <nested tokens> will remain.
То есть если определить \def\mymacro#1#2\relax{...}
и вызвать \mymacro abcd\relax, то 1-м аргументом будет a, а 2-м bcd;
если вызвать \mymacro{ab}cd\relax или \mymacro{ab}{cd}\relax, то 1-м будет ab, а 2-м cd;
если вызвать \mymacro{ab}{c}d\relax, то 1-м будет ab, а 2-м {c}d;
если вызвать \mymacro{}abcd\relax, то 1-м будет пустое слово, а 2-м abcd,
если вызвать \mymacro{abcd}\relax, то 1-м будет abcd, а 2-м пустое слово,
если вызвать \mymacro\relax\relax, то 1-м будет \relax, а 2-м -- пустое слово.
(Проверьте!)
Можно написать, например, \def\mymacro[#1][#2]{...}, тогда вызывать надо будет в формате \mymacro[ab][cd].

\relax\relax нужно для корректного прохождения последней итерации. В начале предпоследней от "азбуки" останется 1 байт, который подставится в качестве #1, в качестве #2 будет пустое слово, а 1-й из этих 2 \relax'ов будет маркером конца аргументов. В результате предпоследней итерации будет вызвано \makeother\relax\relax, поэтому в качестве #1 подставится 1-й \relax, в качестве #2 пустое слово, а 2-й \relax будет маркером конца.

3) Да, \myfootnoteaux -- это макрос с 2 аргументами.

3а) Нет; но тут как раз определение РАНЬШЕ 1-го вызова, потому что 1-й вызов происходит в самом низу, уже после \begin{document}.

3б) Нет. Нет.
Предположим, написано \myfootnote{AAAA}{BBBB}. Сначала выполняется макрос \myfootnote с аргументом AAAA; после этого шага \myfootnote{AAAA}{BBBB} превращается в \begingroup\expandafter\makeother\azbuka\relax\myfootnoteaux{AAAA}{BBBB} (с BBBB пока вообще ничего не происходит). Далее будет раскрыта \azbuka, потом выполнится \makeother, а потом \myfootnoteaux, в который подставятся 2 аргумента: AAAA и BBBB.

3в) Закрывающая есть, она сразу перед \begin{document}.

4) Это не совсем одно и то же. \begingroup спаривается только с \endgroup, но не с }, а { только с }, но не с \endgroup. При определении макроса с помощью \def "замещающий текст" должен быть между {}, а \begingroup и \endgroup не учитываются как ограничители замещающего текста.

 
 
 
 Re: Как обойти \detokenize?
Сообщение28.06.2022, 10:55 
Один \relax в определении \makeother у меня в принципе избыточен: 1-й аргумент не оказывается пустым, поэтому можно так:
Используется синтаксис LaTeX
\def\makeother#1#2\relax{\ifx\relax#1\else\catcode`#1=12\makeother#2\relax\relax\fi}

 
 
 
 Re: Как обойти \detokenize?
Сообщение28.06.2022, 13:25 
Аватара пользователя
Slav-27 в сообщении #1558680 писал(а):
Стандартное место, где искать ответы на такие вопросы, -- The TeXBook, by Don Knuth. Я, как уже говорил, не эксперт: отвечаю в меру своего понимания, относитесь ко мне с недоверием.

1) Да. Да.

2) Да (кроме последней итерации).
The TeXBook, chapter 20 писал(а):
How does TeX determine where an argument stops, you ask. Answer: There are two cases. A delimited parameter is followed in the parameter text by one or more non-parameter tokens, before reaching the end of the parameter text or the next parameter token; in this case the corresponding argument is the shortest (possibly empty) sequence of tokens with properly nested {...} groups that is followed in the input by this particular list of non-parameter tokens. (Category codes and character codes must both match, and control sequence names must be the same.) An undelimited parameter is followed immediately in the parameter text by a parameter token, or it occurs at the very end of the parameter text; in this case the corresponding argument is the next nonblank token, unless that token is ‘ { ’, when the argument will be the entire {...} group that follows. In both cases, if the argument found in this way has the form ‘ { <nested tokens> } ’, where <nested tokens> stands for any sequence of tokens that is properly nested with respect to braces, the outermost braces enclosing the argument are removed and the <nested tokens> will remain.
То есть если определить \def\mymacro#1#2\relax{...}
и вызвать \mymacro abcd\relax, то 1-м аргументом будет a, а 2-м bcd;
если вызвать \mymacro{ab}cd\relax или \mymacro{ab}{cd}\relax, то 1-м будет ab, а 2-м cd;
если вызвать \mymacro{ab}{c}d\relax, то 1-м будет ab, а 2-м {c}d;
если вызвать \mymacro{}abcd\relax, то 1-м будет пустое слово, а 2-м abcd,
если вызвать \mymacro{abcd}\relax, то 1-м будет abcd, а 2-м пустое слово,
если вызвать \mymacro\relax\relax, то 1-м будет \relax, а 2-м -- пустое слово.
(Проверьте!)

Кто бы мог подумать, что для решения такой, казалось бы, простой задачи, как добавление текстовой аннотации к сноске, потребуется столь глубокое копание в столь объёмных и сложных источниках, как Кнутовское описание plain TeX. Процитированный Вами абзац, кстати, у Кнута помечен двойным знаком Z "опасная дорога", что согласно предисловию означает: "Не стоит читать этот абзац, если в этом нет необходимости. Храбрые и опытные исследователи системы TeX будут погружаться в эти области, но для большинства такие подробности излишни". А двойной знак обозначает: "Слишком экзотичные абзацы", для которых: "Всё, что говорилось об одном знаке опасного поворота, удваивается".

Slav-27 в сообщении #1558680 писал(а):
Предположим, написано \myfootnote{AAAA}{BBBB}. Сначала выполняется макрос \myfootnote с аргументом AAAA; после этого шага \myfootnote{AAAA}{BBBB} превращается в \begingroup\expandafter\makeother\azbuka\relax\myfootnoteaux{AAAA}{BBBB} (с BBBB пока вообще ничего не происходит).

Какой хитрый способ добавления второго аргумента! Надо сказать, что я видел нечто похожее вот здесь при обсуждении того, зачем в TeX нужна группировка. В пункте 3 ответа Yiannis Lazarides сказано, что группировка может применяться при необходимости разделения команды на две части, например:

Используется синтаксис LaTeX
 \def\index{\@bsphack\begingroup \@sanitize\@index}
 \def\@index#1{\endgroup\@esphack}

Но без Ваших пояснений я бы ещё нескоро осознал смысл этого кода.

-- Вт июн 28, 2022 14:29:42 --

Вообще, plain TeX на первый взгляд здорово непохож на нормальный язык программирования, поэтому сходу в нём мало что понятно. К сожалению, похоже, что без копания в нём эту задачу не решить.

 
 
 
 Re: Как обойти \detokenize?
Сообщение28.06.2022, 13:51 
Я слышал, что в LuaTeX и XeTeX с Юникодом проще, чем в pdfTeX, но никогда не пользовался и ничего про них не знаю.

epros в сообщении #1558699 писал(а):
К сожалению, похоже, что без копания в нём эту задачу не решить.
Мне кажется, что дальше будет проще. \cite{...} не работает, потому что при его раскрытии получается не только текст [1], но и ещё много чего, в частности, гиперссылка. Осталось получить макрос, который будет после раскрытия выдавать текст и ничего более. Вероятно, такой макрос где-то там уже есть и \cite его вызывает.

-- 28.06.2022, 15:11 --

С \def\mycs{\arabic{section}} всё работает, например.

 
 
 
 Re: Как обойти \detokenize?
Сообщение28.06.2022, 15:11 
Аватара пользователя
Slav-27 в сообщении #1558702 писал(а):
Я слышал, что в LuaTeX и XeTeX с Юникодом проще, чем в pdfTeX, но никогда не пользовался и ничего про них не знаю.

Не знаю, может быть это позволит обходиться без \detokenize, зато заново нужно изучать, какими командами создавать аннотации в PDF. К тому же я слышал, что эти компиляторы ориентированы на использование общесистемных шрифтов, а мне это совсем не нужно, я хочу, чтобы мой PDF создавался строго с включёнными в него шрифтами, т.е. чтобы от системы читателя никак не зависеть.

Slav-27 в сообщении #1558702 писал(а):
Мне кажется, что дальше будет проще. \cite{...} не работает, потому что при его раскрытии получается не только текст [1], но и ещё много чего, в частности, гиперссылка.

Думаю, если бы дело было только в гиперрсылке, то можно было бы обойтись таким кодом:

Используется синтаксис LaTeX
\edef\tmpcite{\begin{NoHyper}\cite{leibniz_tom1}\end{NoHyper}}

Окружение NoHyper выключает гиперссылки, которые создаёт пакет hyperref. Но этот \edef почему-то выдаёт ошибки, так что сразу раскрыть макрос, который создаёт ссылку на литературу с указанием номера источника, не удаётся.

-- Вт июн 28, 2022 16:32:37 --

Похоже, что \cite раскрывается за два прохода. При первом проходе у меня печатается вопросительный знак в квадратных скобках и в сообщениях пишет:
[BibTeX] finished with exit code 2

 
 
 [ Сообщений: 37 ]  На страницу 1, 2, 3  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group