因此,我们有这是用户 Andrew 编写的很棒的正则表达式代码作为对我原帖的回答自动将某些输入(例如标点符号)置于环境/命令之外“:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_word_seq % define a new seqence
\NewDocumentCommand\IterateOverPunctutation{ m m }{
% apply "function" #2 to the "words" in #1 between the punctuation characters
\regex_split:nnN { [\.\,\;\:\s]+ } { #1 } \l_word_seq% split the sequence
\seq_map_function:NN \l_word_seq {#2}% apply #2 to each word in \l_word_seq
}
\ExplSyntaxOff
\begin{document}
\newcommand\Any[1]{``\textbf{#1}''\space}% a dummy \Any command
\IterateOverPunctutation{A, B: C. D}\Any
\end{document}
巧妙地产生了:
事情是这样的:
A, B: C. D
到
“
A
” “
B
” “
C
” “
D
”
但我现在的后续问题是......如何从(这只是一个例子......请参阅Andrew的代码或链接的OP了解更多信息):
A, B: C. D
例如
“
A
”, “
B
”: “
C
”. “
D
”
也就是说,如何还输出/重复分隔符(在本例中分别为,
和.
和.
)?
答案1
该listofitems
包可以使用嵌套的解析级别或(如这里所做的那样)使用多个(等同的)解析分隔符来解析输入。宏\setsepchar{.||,||:}
设置等同的解析字符.
、,
和:
。没有假设最终分隔符(即“D”之后),但如果我误解了条件,可以更改。
而(在我的 MWE 中)\mylist[<i>]
给出第 i 个数据字段,\mylistsep[<i>]
给出第 i 个数据字段后面的分隔符。
\documentclass{article}
\usepackage{listofitems}
\newcommand\punctiterate[1]{%
\setsepchar{.||,||:}%
\readlist*\mylist{#1}%
\foreachitem\i\in\mylist{\ifnum\icnt>1\relax\mylistsep[\the\numexpr\icnt-1] \fi``\i''}
}
\begin{document}
\punctiterate{A, B: C. D}
\end{document}
附录
OP 希望将\par
s 嵌入到输入中。为了实现此目标,我使用了 2 级解析,并\par
以 为 2 级解析分隔符。如果 a\par
存在于任何 1 级项目中,则 2 级列表长度为 2,否则为 1。我可以利用这一事实来拦截 a 的存在\par
并采取相应措施。
[更新:Christian 已将listofitems
软件包更新至 V1.4,可从以下网址获取https://ctan.org/tex-archive/macros/generic/listofitems。更新后,\par
可再次用作列表分隔符。]
\documentclass{article}
\usepackage{listofitems}
\newcommand\punctiterate[1]{%
\setsepchar{.||,||:/\par}%
\readlist*\mylist{#1}%
\foreachitem\i\in\mylist{%
\ifnum\listlen\mylist[\icnt]>1\relax\par``\mylist[\icnt,2]''\else%
``\i''\fi\ifnum\icnt<\mylistlen\relax\mylistsep[\icnt] \fi%
}%
}
\begin{document}
\punctiterate{A, B: C. \par D}
\end{document}
答案2
您想要抓取中的分隔符\regex_split:nnN
。这正是组的用途:只需将括号添加到模式中,这些括号匹配的任何内容都会显示在结果序列中。然后,在映射序列时,我们需要跟踪奇数项和偶数项,因为它们分别是单词和分隔符。您可能需要对分隔符应用进一步的正则表达式处理以区分空格和标点符号等等。使用具有多个组(一对括号)的正则表达式来分别抓取两者可能会很有用,例如。然后当然([\.\,\;\:])([\s\c{par}]+)
必须测试序列的循环。\int_mod:nn { \l_word_int } { 3 }
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_word_seq % define a new sequence
\int_new:N \l_word_int % counts words to distinguish words and separators
\NewDocumentCommand\IterateOverPunctutation{ m m m }{
% apply "function" #2 to the "words" in #1 between the punctuation characters
\regex_split:nnN { ([\.\,\;\:\s]+) } { #1 } \l_word_seq% split the sequence
\int_zero:N \l_word_int
\seq_map_inline:Nn \l_word_seq
{
\int_incr:N \l_word_int
\int_if_odd:nTF { \l_word_int }
{ #2 {##1} } % apply #2 to each word in \l_word_seq
{ #3 {##1} } % apply #3 to each separator in \l_word_seq
}
}
\ExplSyntaxOff
\begin{document}
\newcommand\Any[1]{``\textbf{#1}''}% a dummy \Any command
\newcommand\Thing[1]{\underline{#1}}% a dummy \Thing command
\IterateOverPunctutation{A, B: C. D}\Any\Thing
\end{document}
我没有使用,\seq_indexed_map_inline:Nn
因为它是 1 年前才添加的,可能不是每个人都有。有了它,你可以避免需要变量int
。