
Alguns editores de programação e IDEs destacam nomes de variáveis legais e ilegais de diferentes maneiras. Eu gostaria listings
que 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, listings
mas, 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 \Word
macro, até que um .
token seja encontrado. Nessa fase, eu processo \Word
de 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.
\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 \def
fornece texto de parâmetro delimitado. Então, neste caso, você pode usar o espaço como delimitador:
\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}
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}