我习惯于每句话写一行,因为我通常将内容编译为 LaTeX,或者以其他格式编写,而换行符会被忽略。我使用空行来指示新段落的开始。
现在,我有一个以这种风格编写的文件,我想以纯文本形式发送。我想删除所有单换行符,但保留双换行符完好无损。这就是我所做的:
sed 's/^$/NEWLINE/' file.txt | awk '{printf "%s ",$0}' | sed 's/NEWLINE/\n\n/g' > linebreakfile.txt
这会用一些我确信不会出现在文件中的文本替换空行:NEWLINE
然后它会删除所有换行符awk
(我在某些网站上发现了这个技巧),然后它NEWLINE
用必需的两个换行符替换了 s 。
这似乎是做一件非常简单的事情的一种冗长的方法。有没有更简单的方法?另外,如果有一种方法可以用单个空格替换多个空格(有时由于某种原因会出现),那也很好。
我使用 emacs,所以如果有一些 emacs 特定的技巧那很好,但我宁愿看到一个纯粹的sed
或纯粹的awk
版本。
答案1
您可以像这样使用 awk:
$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } ' test
或者,如果您需要在末尾添加额外的换行符:
$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } END { print ""; } ' test
或者,如果您想用换行符分隔段落:
$ awk ' /^$/ { print "\n"; } /./ { printf("%s ", $0); } END { print ""; } ' test
这些 awk 命令利用由模式保护的操作:
/regex/
或者
END
仅当模式与当前行匹配时才会执行以下操作。
并且这些^$.
字符在正则表达式中具有特殊含义,其中^
匹配行的开头、$
结尾和.
任意字符。
答案2
使用 awk 或 Perl段落模式逐段处理文件,段落之间用空行分隔。
awk -vRS= '
NR!=1 {print ""} # print blank line before every record but the first
{ # do this for every record (i.e. paragraph):
gsub(" *\n *"," "); # replace newlines by spaces, compressing spaces
sub(" *$",""); # remove spaces at the end of the paragraph
print
}
'
perl -000 -pe ' # for every paragraph:
print "\n" unless $.==1; # print a blank line, except before the first paragraph
s/ *\n *(?!$)/ /g; # replace newlines by spaces, compressing spaces, but not at the end of the paragraph
s/ *\n+\z/\n/ # normalize the last line end of the paragraph
'
当然,由于这不会解析 (La)TeX,因此它会严重破坏注释、逐字环境和其他特殊语法。您可能想了解一下德特克斯或其他 (La)TeX 到文本转换器。
答案3
(复活一个古老的问题)
这似乎正是fmt
和par
的用途 - 段落重新格式化。像您一样(也像许多程序一样),他们将段落边界定义为一个(或多个)空行。尝试通过其中之一管道传输文本。
fmt
是一个标准的 unix 实用程序,可以在 GNU Coreutils 中找到。
par
是 Adam M. Costello 编写的一个大大增强的fmt
版本,可以在以下位置找到:http://www.nicemice.net/par/(它也被打包用于多个发行版,包括 debian - 我在 1996 年 1 月将它打包为 debian,尽管现在有一个新的 pkg 维护者。)。
答案4
如果我理解正确的话,空行意味着两个连续的换行符,\n\n
.
如果是这样,一种可能的解决方案是消除所有单独出现的换行符。
在 Perl 中,前瞻断言是实现此目的的一种方法:
$ perl -0777 -i -pe 's/\n(?=[^\n])//g' test
- 该
-0777
标志有效地将整个文件合并为单个字符串 -p
告诉 perl 默认打印它正在处理的字符串-i
指定就地编辑- 全局匹配确保处理所有单个换行符出现