Como posso analisar a primeira palavra em um fluxo de token, token por token?

Como posso analisar a primeira palavra em um fluxo de token, token por token?

Alguns editores de programação e IDEs destacam nomes de variáveis ​​legais e ilegais de diferentes maneiras. Eu gostaria listingsque essa verificação e realce de sintaxe fossem facilmente permitidos, mas isso não acontece, pelo menos no momento. Meu objetivo de longo prazo é implementar uma solução compatível, listingsmas, por enquanto, estou olhando para uma versão muito simplificada do problema.

Quero analisar a primeira palavra em um fluxo de token composto apenas por tokens de caracteres e espaços. Isso tem que ser feitotoken por token, porém, porque preciso realizar algumas verificações em cada token. Para isso, utilizo uma macro recursiva que analisa o stream, salvando-o em uma \Wordmacro, até que um .token seja encontrado. Nessa fase, eu processo \Wordde uma certa forma, como imprimir em vermelho. Eu defino umpalavracomo uma sequência de fichas de caracteres ininterruptas por qualquer ficha de espaço.

Problema: Eu uso apenas um .token aqui porque não consigo descobrir o que devo alterar em meu código para interromper a recursão quando o próximo token de espaço, e não um .token, for encontrado no fluxo. Substituir um espaço de controle ( \) por .não parece funcionar. O que devo mudar no meu código?

Eu sou a favor de uma solução que use comandos TeX de baixo nível para análise, mas as alternativas LaTeX2e e LaTeX3 também são do meu interesse.

Editar: Peço desculpas se parece que estou movendo a trave, mas tive que esclarecer um pouco minha pergunta adicionando o requisito "token por token", o que pode invalidar algumas das respostas já postadas.

insira a descrição da imagem aqui

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

Responder1

Recuperando isso à luz da sua pergunta editada.

É mais fácil pegar a palavra de uma só vez com um argumento delimitado por espaço eentãoiterar sobre essa letra por letra. (Como exemplo verifico aqui que são letras, o último exemplo produz

illegal character 0
illegal character 1

Para iterar caractere por caractere, parando em um espaço que você deve usar \futurelet(ou equivalente \@ifnextchar), mas isso não é tão bom em uma palavra que você irá compor, pois é difícil não quebrar núcleos e ligaduras entre letras. Portanto, é mais fácil entender a palavra primeiro.

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

Responder2

O TeX \deffornece texto de parâmetro delimitado. Então, neste caso, você pode usar o espaço como delimitador:

insira a descrição da imagem aqui

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

Responder3

É muito fácil com 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}

insira a descrição da imagem aqui


Se você também quiser processar o token de entrada por token, poderá fazer um mapeamento nos itens salvos. Digamos que você queira colocar cada 'd' em maiúscula:

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

insira a descrição da imagem aqui

informação relacionada