¿Cómo puedo analizar la primera palabra en una secuencia de tokens, token por token?

¿Cómo puedo analizar la primera palabra en una secuencia de tokens, token por token?

Algunos editores de programación e IDE resaltan nombres de variables legales e ilegales de diferentes maneras. Desearía listingsque se permitiera fácilmente dicha verificación y resaltado de sintaxis, pero no es así, al menos por el momento. Mi objetivo a largo plazo es implementar una solución compatible con listingspero, por ahora, estoy viendo una versión muy simplificada del problema.

Quiero analizar la primera palabra en una secuencia de tokens compuesta únicamente de tokens de caracteres y espacios. esto tiene que hacerseficha por ficha, sin embargo, porque tengo que realizar algunas comprobaciones en cada token. Para eso, utilizo una macro recursiva que analiza la secuencia y la guarda en una \Wordmacro hasta que .se encuentra un token. En esa etapa, proceso \Wordde cierta manera, como imprimirlo en rojo. Yo defino unpalabracomo una secuencia de fichas de personaje ininterrumpida por ninguna ficha de espacio.

Problema: Aquí solo uso un .token porque no puedo entender qué debo cambiar en mi código para detener la recursividad cuando .se encuentra el siguiente token de espacio, no un token, en la secuencia. Sustituir un espacio de control ( \) .no parece funcionar. ¿Qué debo cambiar en mi código?

Prefiero una solución que utilice comandos TeX de bajo nivel para el análisis, pero las alternativas LaTeX2e y LaTeX3 también me interesan.

Editar: Pido disculpas si parece que estoy moviendo la portería, pero tuve que aclarar bastante mi pregunta agregando el requisito "token por token", lo que puede invalidar algunas de las respuestas ya publicadas.

ingrese la descripción de la imagen aquí

\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}

Respuesta1

Recuperando esto a la luz de su pregunta editada.

Es más fácil captar la palabra de una vez con un argumento delimitado por espacios yentoncesiterar sobre esa letra por letra. (Como ejemplo compruebo aquí que son letras, el último ejemplo produce

illegal character 0
illegal character 1

Para iterar carácter por carácter deteniéndote en un espacio que debes usar \futurelet(o equivalentemente \@ifnextchar), pero eso no es tan bueno en una palabra, vas a componer, ya que es difícil no romper los núcleos y ligaduras entre letras. Así es más fácil captar la palabra primero.

\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}

Respuesta2

TeX \defproporciona texto de parámetro delimitado. Entonces, en este caso, puedes usar el espacio como delimitador:

ingrese la descripción de la imagen aquí

\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}

Respuesta3

Es realmente fácil con 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}

ingrese la descripción de la imagen aquí


Si también desea procesar la entrada token por token, puede realizar un mapeo de los elementos guardados. Digamos que quieres poner en mayúscula cada '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}

ingrese la descripción de la imagen aquí

información relacionada