Shell 用正则表达式格式化带有脚注的文本
我想把文本的注释转换成脚注的形式。这里是一个最小的文本示例 第一段。这是第一段的第一位。这是第一段的第二位[2] [1] 第一段注释一 [2] 第一段注释二 第二段。这是第二段的第一位。这是第二段的第二位[2] [1] 第二款注释一 [2] 第二段注释二 在每个段落的末尾,都会有几个以标签[1]开头的注释。每个注释将形成一个段落 我想做的是用latex语法将这些注释插入到文本中。示例文本的所需输出为 第一段。这是第一段的第一个位置。这是第一段的第二位 第二段。这是第二段的第一个位置。这是第二段的第二位 这不仅仅是一个简单的模式匹配替代。它可能必须以段落为基础进行。你认为最简单的方法是什么 编辑:为了使用sed,我想出了一个可能的解决方案 删除注释前面的换行符 第一段。这是第一段的第一位。这是第一段的第二位[2]。[1] 第一段注释一[2]第一段注释二 第二段。这是第二段的第一位。这是第二段的第二位[2]。[1] 第二段注释一[2]第二段注释二 匹配模式 [1] text1[1]text2[2] 并将其替换为 text2text1[2] 基本上,第一个[1]是插入注释的位置;[1]和[2]之间的内容是要重新定位的注释Shell 用正则表达式格式化带有脚注的文本,shell,perl,sed,footnotes,Shell,Perl,Sed,Footnotes,我想把文本的注释转换成脚注的形式。这里是一个最小的文本示例 第一段。这是第一段的第一位。这是第一段的第二位[2] [1] 第一段注释一 [2] 第一段注释二 第二段。这是第二段的第一位。这是第二段的第二位[2] [1] 第二款注释一 [2] 第二段注释二 在每个段落的末尾,都会有几个以标签[1]开头的注释。每个注释将形成一个段落 我想做的是用latex语法将这些注释插入到文本中。示例文本的所需输出为 第一段。这是第一段的第一个位置。这是第一段的第二位 第二段。这是第二段的第一个位置。这是第二段的
这些问题是相关的:,但我不能让这些代码为我工作,因为我缺乏正则表达式的知识。基本上,
sed
是这个工作的错误工具。您可能能够编写一个sed
脚本来预处理文件,并生成一个新的sed
脚本来处理文件,但当有许多更好的工具用于此任务时,您就要抓紧救命稻草了。我想学习Perl(但我在20多年前就学会了Perl,而Python在几年前才学会),但Python也能够处理它,而且您甚至可以小心地使用awk
。问题的一部分是,你必须保存第一段的所有文本,直到你到达第二段的开头;只有这样,您才能开始生成第一段的实际文本
我认为“sed
是错误的工具”注释仍然有效,即使sed
脚本捕获了保留空间中的段落内容。这些线不是以方括号开始的。问题是,当您遇到一个方括号的行时,您需要编写一个正则表达式,将行尾替换为保留空间,以代替方括号的内容。这需要一种“动态正则表达式”。即使你知道在段落中永远不会有超过,比如说9个脚注,所以你可以考虑写出9次代码的黑客,在正确的地方写替换字符串仍然存在问题。
这里有一个简单的Perl脚本——这是一个不太复杂的Perl脚本——可以完成这项工作。“旋转循环”(三个嵌套循环)使得理解起来有点困难
#!/usr/bin/env perl
use strict;
use warnings;
my $para = "";
TEXT:
while (<>)
{
NOTES:
while (m/^\s*\[(\d+)]\s+(.*)/)
{
my $tag = $1;
my $note = $2;
$para =~ s/\[$tag]/\\footnote{$note}/m;
while (<>)
{
last if $_ =~ m/^\s*\[/;
if ($_ !~ m/^\s*$/)
{
print $para;
$para = "";
last NOTES;
}
}
last TEXT if eof;
}
$para .= $_;
}
print "$para";
该文件中此脚本的输出为:
Paragraph one. This is the first place \footnote{annotation one of paragraph one} of paragraph one. This is the second place \footnote{annotation two of paragraph one} of paragraph one.
Paragraph two. This is the first place \footnote{annotation one of paragraph two} of paragraph two. This is the second place \footnote{annotation two of paragraph two} of paragraph two.
剧本是做什么的
外部循环(标记为TEXT
)将行读入$\uuu
,直到EOF
标记为NOTES
的循环处理段落后的材料,直到下一段开始。它知道这是一个脚注行,因为它以方括号中的一个数字开始(可能以空格缩进,并且肯定在紧闭的方括号后面有空格)。当它找到这样一行时,数字保存在$tag
中,替换文本(必须是单行-此处没有扩展的多行脚注)保存在$note
中。然后,保存段落中方括号内第一次出现的标记将替换为脚注符号和注释文本(这一部分几乎不可能在一次运行sed
时出现,并且由于脚注编号在段落之间重复,因此即使运行两次sed
也会出现问题)。完成替换后(不管是否有匹配项可替换),它会读取下一行,这就是循环(和头部)开始旋转的地方。如果新读取的行是注释行,则初始的last
退出最内层的while
,并返回到NOTES
循环的下一次迭代。如果该行与空行不匹配,那么我们必须刚刚阅读下一段的第一行,因此打印上一段(现在替换的数量与要替换的数量相同),清空保存的段落,然后退出注释
循环。否则,忽略注释中间的空行。
循环结束后,检查是否获得EOF,如果获得EOF,则退出主循环。否则,将刚刚读取的段落行添加到保存的段落中
最后,打印最后保存的段落
这还没有经过详尽的测试。我没有生成引用缺失注释的段落,或者没有引用的注释,或者没有顺序的注释
Paragraph one. This is the first place \footnote{annotation one of paragraph one} of paragraph one. This is the second place \footnote{annotation two of paragraph one} of paragraph one.
Paragraph two. This is the first place \footnote{annotation one of paragraph two} of paragraph two. This is the second place \footnote{annotation two of paragraph two} of paragraph two.
perl -00 -pe '
@markers = m{(\[\d+\])}g;
for $i (0..$#markers) {
$footnote = <>;
($marker, $text) = $footnote =~ m{(\[\d+\])\s+(.*)};
s{\Q$marker\E}{\\footnote{$text}};
}
' file