用于解开多个段落的简单过滤器

用于解开多个段落的简单过滤器

我有许多 Markdown 文件,它们被硬包装到 80 个字符。我想复制这些内容以粘贴到文本区域(xclip -sel clipboard < file)中,但希望它们正常换行。这很简单,没有段落 - tr "\n" " " < file | xclip -sel clipboard,但将所有文本变成连续段落,仍然需要手动复制编辑。

是否有一个简短的过滤器使用标准 *NIX 工具(GNU 版本很好)来删除所有“\n”除了当有两个彼此相邻时?最好是我能记住并重新输入的内容 - 少于 30 个字符且没有文件。感觉应该sed能做点什么。

答案1

你可以使用perl

例如,使用以下硬包装示例输入文件:

$ cat input.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
$ perl -0777 -p -e 's/(?<!\n)\n/ /g' input.txt 
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

或者,如果您仍然希望每个段落之间有一个空行:

$ perl -0777 -p -e 's/(?<!\n)\n/ /g; s/\n/\n\n/g' input.txt 
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

注意:除非输入以一个或多个空行结束,否则输出的最后一行不会有换行符。如果需要,请添加; END {print "\n"}到脚本末尾。这将保证输出以换行符结束。

-0777选项告诉 perl 一次性“slurp”其输入文件,并将其作为一个长字符串进行处理。

上面的单行代码的两个版本都使用了 perl 正则表达式的一项功能,称为“零宽度负向后断言”- (?<!pattern)。有关详细信息,请参阅man perlre并搜索“Lookaround Assertions”。简而言之,(?<!\n)\n匹配换行符除非它之前的字符是另一个换行符 - 并且它在没有实际匹配或捕获前面的字符的情况下执行此操作(这就是“零宽度断言”的含义)。

如果不使用否定后断言,您可能会想做类似的事情s/[^\n]\n/ /g- 但这最终会删除每个换行符之前的每个字符......这就是正则表达式的零宽度部分很重要的原因,它可以防止这种情况发生。另一种替代方法是使用类似的s/([^\n])\n/\1 /g方法捕获换行符之前的字符并将其用于替换 - 例如使用 GNU sed:sed -E -z 's/([^\n])\n/\1 /g' input.txt但在我看来,最好根本不匹配前面的字符,而不是匹配并删除它,然后将其放回去。

其他一些正则表达式引擎也支持环视断言,但它们是非标准的,因此不能保证受到支持。

答案2

tr "\n" " " < file | sed 's/ /\n/g;s/ $//'可能会正常工作。它需要单行距句子(有些人讨厌)来重新添加段落换行符。它还会修剪文件最后一行中添加的空间。

相关内容