一些编程编辑器和 IDE 以不同的方式突出显示合法和非法的变量名。我希望listings
能够轻松实现这种语法检查和突出显示,但至少目前还不行。我的长期目标是实现一个兼容的解决方案listings
,但目前,我正在寻找一个非常简化的问题版本。
我想解析仅由字符和空格标记组成的标记流中的第一个单词。必须这样做逐个标记,因为我必须对每个 token 执行一些检查。为此,我使用递归宏来解析流,将其保存在宏中\Word
,直到.
遇到 token。在那个阶段,我\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\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}