我想使用 LaTeX3 正则表达式从文本中提取“行”,如下所示:
- First line
- second line ending with \LaTeX
- third line with - in the middle
- fourth line that
goes on for a bit
我所说的“行”是指以-
“物理行”开头的破折号开头的文本,一直延续到下一个这样的破折号或字符串的末尾。
我的第一个猜测是,类似下面的方法可以起作用:
\regex_split:nVN { [\f\n\r]\s+-\s+ } { \Lines } \l_tmp_seq
我的理解是,这应该匹配一个“换行符”,后面跟着-
一个两边都是空格的字符。不幸的是,这很糟糕,只产生了一个匹配:
由于这不起作用,我想我会尝试一种非常简单的方法,只需在空白包围的破折号上拆分字符串-
。这会在行上产生错误的结果,例如上面的第三行,但我可以--
在行的中间使用,所以这是一个可行的替代方案。由于\s
匹配空白,以下应该在上拆分行-
:
\regex_split:nVN { \s+-\s+ } { \Lines } \l_tmp_seq
这样比较好,但是结果仍然不完美,因为除了第 3 行预期的问题之外,\LateX
在行尾出现 也会引起混淆,\regex_split
大概是因为宏往往会吞掉空格:
我发现的最佳解决方案是使用:
\regex_split:nVN { \B-\B } { \Lines } \l_tmp_seq
这将产生我期望从最后一个正则表达式获得的输出:
也就是说,我们-
在第三行中间得到了不想要的匹配,但除此之外没有问题。
问题是否存在不返回任何错误匹配的正则表达式?允许初始和/或最终匹配空序列。
[附言:我并不担心上面的“空”初始序列,因为我知道可以使用
\seq_pop_left:NN \l_tmp_seq \l_tmpa_tl % pop initial blank
当然,终止空序列可以使用几乎完全相同的方式处理\seq_pop_right:NN
。]
以下是生成上述示例的完整 MWE:
\documentclass{article}
\usepackage{xparse}
\parindent=0pt
\newcommand\BS{$\backslash$}
\newcommand\Test[1]{\textbf{Testing:}\quad\texttt{#1}}
\begin{document}
\newcommand\Lines{
- First line
- second line ending with \LaTeX
- third line with -- in the middle
- fourth line that
goes on for a bit
}
\ExplSyntaxOn
\seq_new:N \l_tmp_seq
\cs_generate_variant:Nn \regex_split:nnN { nVN }
\Test{[\BS f\BS n\BS r]\BS s+-\BS s+}
\regex_split:nVN { [\f\n\r]\s+-\s+ } { \Lines } \l_tmp_seq
\begin{itemize}\item\seq_use:Nn \l_tmp_seq {\item }\end{itemize}
\Test{\BS s-\BS s}
\regex_split:nVN { \s-\s } { \Lines } \l_tmp_seq
\begin{itemize}\item\seq_use:Nn \l_tmp_seq {\item }\end{itemize}
\Test{\BS B-\BS B}
\regex_split:nVN { \B-\B } { \Lines } \l_tmp_seq
\begin{itemize}\item\seq_use:Nn \l_tmp_seq {\item }\end{itemize}
\ExplSyntaxOff
\end{document}
在正则表达式中转义-
也无济于事。
最后,问题可能是在定义时删除了换行符\Lines
。据我所知,这是可以的,因为上面的代码给出了类似的输出。特别是,如果我使用:
\documentclass{article}
\usepackage{xparse}
\parindent=0pt
\begingroup\obeylines
\gdef\Lines{
- First line
- second line ending with \LaTeX
- third line with -- in the middle
- third line that
goes on for a bit
}
\endgroup
\begin{document}
\ExplSyntaxOn
\seq_new:N \l_tmp_seq
\cs_generate_variant:Nn \regex_split:nnN { nVN }
\regex_split:nVN { [\f\n\r]\s+\-\s+ } { \Lines } \l_tmp_seq
Sequence~length:~ \seq_count:N \l_tmp_seq.
\begin{itemize}\item\seq_use:Nn \l_tmp_seq {\item }\end{itemize}
\ExplSyntaxOff
\end{document}
然后我得到输出:
在实践中,我得到的\Lines
是\BODY
环境环境,所以我实际上没有这个定义的奢侈......
答案1
您需要 obelines 或类似的东西,这样换行符就不会消失。下面将按需要(几乎)拆分行。\^^M
也可以使用\r
(我只使用了第一个,因为\show\Lines
显示了^^M
)。
这将创建以下序列:
The sequence \l_tmp_seq contains the items (without outer braces):
> {First line}
> {second line ending with \LaTeX }
> {third line with -- in the middle}
> {fourth line that^^Mgoes on for a bit^^M}.
<recently read> }
一个问题可能是第四项包含一个^^M
可能不需要的换行符。
\documentclass{article}
\usepackage{xparse}
\parindent=0pt
\newcommand\BS{$\backslash$}
\newcommand\Test[1]{\textbf{Testing:}\quad\texttt{#1}}
\begin{document}
\begingroup
\obeylines
\gdef\Lines{
- First line
- second line ending with \LaTeX
- third line with -- in the middle
- fourth line that
goes on for a bit
}
\endgroup
\ExplSyntaxOn
\seq_new:N \l_tmp_seq
\cs_generate_variant:Nn \regex_split:nnN { nVN }
\Test{}\verb+^^M\-+
\regex_replace_once:nnN { \A\^^M?\-\s* } {} \Lines %to get rid of the first ^^M
\regex_split:nVN { \^^M\-\s* } \Lines \l_tmp_seq
\begin{itemize}\item\seq_use:Nn \l_tmp_seq {\item }\end{itemize}
\ExplSyntaxOff
\end{document}