
Некоторые редакторы программирования и IDE подсвечивают допустимые и недопустимые имена переменных по-разному. Хотелось бы, listings
чтобы такую проверку синтаксиса и подсветку можно было легко разрешить, но это не так, по крайней мере на данный момент. Моя долгосрочная цель — реализовать решение, совместимое с listings
, но сейчас я рассматриваю очень упрощенную версию проблемы.
Я хочу разобрать первое слово в потоке токенов, состоящем только из токенов символов и пробелов. Это должно быть сделанотокен за токеном, хотя, потому что мне нужно выполнить некоторые проверки для каждого токена. Для этого я использую рекурсивный макрос, который анализирует поток, сохраняя его в макросе \Word
, пока .
не встретится токен. На этом этапе я обрабатываю \Word
определенным образом, например, печатаю его красным цветом. Я определяюсловокак последовательность символов, не прерываемая никакими пробелами.
Проблема: Я использую .
токен только здесь, потому что не могу понять, что мне следует изменить в моем коде, чтобы остановить рекурсию, когда .
в потоке встречается следующий токен пробела, а не токен. Замена на управляющий пробел ( \
) .
не срабатывает. Что мне следует изменить в моем коде?
Я предпочитаю решение, использующее низкоуровневые команды TeX для синтаксического анализа, но альтернативы LaTeX2e и LaTeX3 также представляют для меня интерес.
Редактировать: Прошу прощения, если вам кажется, что я меняю курс, но мне пришлось немного прояснить свой вопрос, добавив требование «токен за токеном», что может сделать недействительными некоторые из уже опубликованных ответов.
\documentclass{article}
\usepackage{xcolor}
\def\ParseWordandPrint#1{%
\if #1.%
\textcolor{red}{\Word}\ %
\else
\edef\Word{\Word#1}
\expandafter\ParseWordandPrint
\fi%
}
\def\InitParseWordandPrint#1{%
\def\Word{}
\ParseWordandPrint#1%
}
\begin{document}
\InitParseWordandPrint Hello.World
\end{document}
решение1
Отменяю удаление в связи с вашим отредактированным вопросом.
Проще ухватить слово за один раз, используя аргумент, разделенный пробелом, изатемперебираем каждую букву. (В качестве примера я проверяю, что это буквы, последний пример выдает
illegal character 0
illegal character 1
Для итерации символ за символом, останавливаясь на пробеле, который вы, вероятно, должны использовать \futurelet
(или эквивалентно \@ifnextchar
), но это не так хорошо в слове, которое вы собираетесь набрать, так как трудно не нарушить межбуквенные керны и лигатуры. Поэтому проще сначала схватить слово.
\documentclass{article}
\usepackage{xcolor}
\def\InitParseWordandPrint#1 {\check#1\relax\textcolor{red}{#1} }
\def\check#1{%
\ifx\relax#1%
\else
\ifcat a#1%
\else
\typeout{illegal character #1}%
\fi
\expandafter\check
\fi}
\begin{document}
\InitParseWordandPrint Hello World
\InitParseWordandPrint World
Hello World
\InitParseWordandPrint W0r1d
\end{document}
решение2
TeX's \def
предоставляет текст параметра с разделителями. Так что в этом случае вы можете использовать пробел в качестве разделителя:
\documentclass{article}
\usepackage{xcolor}
\def\ParseWordandPrint#1{%
\if #1.%
\textcolor{red}{\Word}\ %
\else%
\edef\Word{\Word#1}%
\expandafter\ParseWordandPrint%
\fi%
}
\def\InitParseWordandPrint#1{%
\def\Word{}%
\ParseWordandPrint#1%
}
\def\highlightfirst#1 {\textcolor{red}{#1} }
\begin{document}
\InitParseWordandPrint Hello.World
\highlightfirst Hello World.
\end{document}
решение3
С LaTeX3 это действительно просто:
\documentclass{article}
\usepackage{xparse,xcolor}
\ExplSyntaxOn
\NewDocumentCommand{\printfirstwordincolor}{ O{red} m }
{
\jubobs_pfwr:nn { #1 } { #2 }
}
\seq_new:N \l_jubobs_words_seq
\tl_new:N \l_jubobs_first_word_tl
\cs_new_protected:Npn \jubobs_pfwr:nn #1 #2
{
% split the input at spaces
\seq_set_split:Nnn \l_jubobs_words_seq { ~ } { #2 }
% pop off the leftmost item
\seq_pop_left:NN \l_jubobs_words_seq \l_jubobs_first_word_tl
% print the first item in the chosen color
\textcolor{#1}{ \l_jubobs_first_word_tl } ~ %
% print the other items adding spaces between them
\seq_use:Nn \l_jubobs_words_seq { ~ }
}
\ExplSyntaxOff
\begin{document}
\printfirstwordincolor{Hello World}
\printfirstwordincolor[green]{Addio mondo crudele}
\end{document}
Если вы также хотите обрабатывать входной токен за токеном, вы можете сделать сопоставление сохраненных элементов. Допустим, вы хотите сделать заглавными все 'd':
\documentclass{article}
\usepackage{xparse,xcolor}
\ExplSyntaxOn
\NewDocumentCommand{\printfirstwordincolor}{ O{red} m }
{
\jubobs_pfwc:nn { #1 } { #2 }
}
\seq_new:N \l_jubobs_words_seq
\tl_new:N \l_jubobs_first_word_tl
\bool_new:N \l_jubobs_first_item_bool
\cs_new_protected:Npn \jubobs_pfwc:nn #1 #2
{
\seq_set_split:Nnn \l_jubobs_words_seq { ~ } { #2 }
\seq_pop_left:NN \l_jubobs_words_seq \l_jubobs_first_word_tl
\textcolor{#1}{ \l_jubobs_first_word_tl } ~ %
\seq_use:Nn \l_jubobs_words_seq { ~ }
}
\NewDocumentCommand{\printfirstwordincolorandcapitalizeD} { O{red} m }
{
\jubobs_pfwcacd:nn { #1 } { #2 }
}
\cs_new_protected:Npn \jubobs_pfwcacd:nn #1 #2
{
\seq_set_split:Nnn \l_jubobs_words_seq { ~ } { #2 }
\leavevmode
\bool_set_true:N \l_jubobs_first_item_bool
\seq_map_inline:Nn \l_jubobs_words_seq
{
\bool_if:NT \l_jubobs_first_item_bool
{ \c_group_begin_token \color{#1} }
\tl_map_inline:nn { ##1 }
{
\peek_charcode_remove:NT d { D } ####1
}
\bool_if:NT \l_jubobs_first_item_bool
{ \c_group_end_token \bool_set_false:N \l_jubobs_first_item_bool }
\c_space_tl
}
\unskip
}
\ExplSyntaxOff
\begin{document}
\printfirstwordincolor{Hello World}
\printfirstwordincolorandcapitalizeD[blue]{Addio mondo crudele}
\end{document}