必须有更好的方法来仅替换单个换行符吗?

Sea*_*mus 34 sed awk text-processing regular-expression

我习惯于每句话写一行,因为我通常将内容编译为 LaTeX,或者以其他格式编写,其中换行符会被忽略。我使用一个空行来表示一个新段落的开始。

现在,我有一个以这种风格编写的文件,我只想将其作为纯文本发送。我想删除所有单换行符,但保持双换行符完好无损。这就是我所做的:

sed 's/^$/NEWLINE/' file.txt | awk '{printf "%s ",$0}' | sed 's/NEWLINE/\n\n/g' > linebreakfile.txt
Run Code Online (Sandbox Code Playgroud)

这将用我确信不会出现在文件中的一些文本替换空行:NEWLINE然后它摆脱了所有换行符awk(我在某个网站上发现了这个技巧),然后NEWLINE用必要的两个换行符替换了s。

这似乎是做一件非常简单的事情的冗长方法。有没有更简单的方法?此外,如果有一种方法可以用单个空格替换多个空格(有时出于某种原因会出现),那也很好。

我使用 emacs,所以如果有一些 emacs 特定的技巧是好的,但我宁愿看到一个纯粹的sed或纯粹的awk版本。

max*_*zig 25

您可以像这样使用 awk:

$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } ' test
Run Code Online (Sandbox Code Playgroud)

或者,如果您在最后需要一个额外的换行符:

$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } END { print ""; } ' test
Run Code Online (Sandbox Code Playgroud)

或者,如果您想用换行符分隔段落:

$ awk ' /^$/ { print "\n"; } /./ { printf("%s ", $0); } END { print ""; } ' test
Run Code Online (Sandbox Code Playgroud)

这些 awk 命令使用由模式保护的操作:

/regex/
Run Code Online (Sandbox Code Playgroud)

或者

END
Run Code Online (Sandbox Code Playgroud)

仅当模式与当前行匹配时才会执行以下操作。

并且^$.字符在正则表达式中具有特殊含义,其中^匹配行首、$行尾和.任意字符。


Gil*_*il' 12

使用 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
'
Run Code Online (Sandbox Code Playgroud)

当然,由于这不解析 (La)TeX,它会严重破坏注释、逐字环境和其他特殊语法。您可能需要查看DeTeX或其他 (La)TeX 到文本转换器。


cas*_*cas 10

(重温一个古老的问题)

这似乎是什么fmt以及par是-段落重新格式化。像您一样(也像许多程序一样),他们将段落边界定义为一个(或多个)空行。尝试通过其中之一来管道您的文本。

fmt 是一个标准的 unix 实用程序,可以在 GNU Coreutils 中找到。

parfmt由 Adam M. Costello 编写的大大增强的,可以在http://www.nicemice.net/par/找到(它还被打包用于多个发行版,包括 debian - 我在 1996 年 1 月为 debian 打包了它,虽然现在有一个新的 pkg 维护者。)。

  • `fmt` 对于短句子非常有效,但对于长句子来说效果很好,并且没有“--width=infinite”选项。 (2认同)

Ste*_*n D 9

解决方案

$ sed -e ':a;N;$!ba;s/\(.\)\n/\1 /g' -e 's/\n/\n\n/' test.text
Run Code Online (Sandbox Code Playgroud)

请注意,在此解决方案中:a是创建标签而不是使用a命令。

替换多个空格

使用tr$ tr -s ' ' <test.text


Zai*_*aid 8

如果我理解正确的话,一个空行意味着两个连续的换行符,\n\n.

如果是这样,一种可能的解决方案是消除所有单次出现的换行符。

在 Perl 中,先行断言是实现此目的的一种方法:

$ perl -0777 -i -pe 's/\n(?=[^\n])//g' test
Run Code Online (Sandbox Code Playgroud)
  • -0777标志有效地将整个文件变成了一个字符串
  • -p 告诉 perl 默认打印它正在处理的字符串
  • -i 指定就地编辑
  • 全局匹配确保处理所有单个换行符


mik*_*erv 6

sed -e'/./{H;$!d;}' -e'x;s/\n//g'
Run Code Online (Sandbox Code Playgroud)

sed will append any line to Hold space which contains at least a single character. It immediately thereater deletes all of those excepting perhaps the last. The only lines which can remain are blanks, and it is on these lines when sed exchanges the hold and pattern spaces and deletes all accumulated \newline characters.

如果您希望仅包含<tabs><spaces> 的行被视为空白,请将/./上面的地址替换为/[^[:blank:]]/. 还要挤压空间,请执行以下操作:

 sed -e'/./{H;$!d;}'    \
     -e'x;s/\n//g'      \
     -e's/\([[:blank:]]\)*/\1/g'
Run Code Online (Sandbox Code Playgroud)