Как можно разобрать первое слово в потоке токенов, токен за токеном?

Как можно разобрать первое слово в потоке токенов, токен за токеном?

Некоторые редакторы программирования и 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}

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

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