如何修复在错误的地方折断的线?


11

我的文本文件如下所示:

This is one
sentence that is broken.
However this is a good one.
And this
one is
somehow, broken into
many.

我想删除任何行的尾随换行符,其后是以小写字母开头的行。

所以这应该是:

This is one sentence that is broken.
However this is a good one.
And this one is somehow, broken into many.

我怎样才能做到这一点?

编辑:这里有一些非常好的答案,但是我选择接受第一个可行最早的答案。非常感谢大家!


1
胶乳?问题是您没有真正陈述正确断句的规则。您是否想将所有内容(包括句子标点符号)放在一行上?但是,如果您的句子很长并且超出显示窗口的边缘怎么办?
jamesqf

1
我想知道您真正要解决的是什么?也许您应该使用markdown格式?
通配符

@JeffSchaller感谢您的提醒!我以某种方式错过了。:)

Answers:


7

尝试

awk '$NF !~ /\.$/ { printf "%s ",$0 ; next ; } {print;}' file

哪里

  • $NF !~ /\.$/ 匹配线,其中最后一个元素不以点结尾,
  • { printf "%s ",$0 打印此行时要有一个空格,没有换行,
  • next ; } 获取下一行,
  • {print;} 并打印出来。

我敢肯定会有一个sed选择。

注意:这适用于以点结尾的行,但是以大写字母开头的句子中的条件不会合并。请参阅StéphaneChazelas的答案。


如果您喜欢聪明(很多不喜欢)awk 'ORS=$NF~/\.$/?"\n":" "'
dave_thompson_085

10

awk

awk -v ORS= '{print (NR == 1 ? "" : /^[[:lower:]]/ ? " " : RS) $0}
             END {if (NR) print RS}'

即,不要将记录分隔符附加到每一行(ORS为空)。但前面加上当前行之前记录分隔如果不是在第一行和当前行不以小写字母开头。否则,除了第一行外,在前面加上一个空格字符。


当我运行此命令时,一些单词对是串联在一起的。例如,And thisone issomehow, broken intomany.我不知道,awk但是<space>除了行之外,还应该加入行RS吗?还是这个用户错误?
B层

@鲍耶,发现得很好,谢谢。现在应该修复。
斯特凡Chazelas

没问题。尽管有人想知道这11个投票的来源。让人们只是假设您永远是对的,一定很高兴。;)
B层

4

在perl中:

#!/usr/bin/perl -w
use strict;
my $input = join("", <>);
$input =~ s/\n([a-z])/ $1/g;
print $input;

从技术上讲,您希望将“换行符后的小写字母”替换为“空格和-那个小写字母”,这是上述perl脚本的核心功能:

  1. 将输入读入字符串input
  2. input变量更新为搜索和替换操作的结果。
  3. 打印新值。

1
好一个!转换为单行代码,perl -0777 -pe 's/\n([a-z])/ $1/g'并且可以类似地使用GNU sed做为sed -zE 's/\n([a-z])/ \1/g'(假设输入没有空字符)
Sundeep

3
@Sundeep,或者perl -Mopen=locale -0777 -pe 's/\n(?=[[:lower:]])/ /g'不限于ASCII字母。
斯特凡Chazelas

4

有了sed你可以使用一个N;P;D周期(以总是在模式空间两条直线,如果换行后的第一个字符是小写然后替换用空间换行)和tEST -以后每次这样substitution重新启动循环:

sed -e :t -e '$!N;/\n[[:lower:]]/s/\n/ /;tt' -e 'P;D' infile

1
我想我知道这里发生了什么,但是扩展的答案将帮助那些不经常使用sed循环和模式空间的人。

@Joe- “不经常使用模式空间”是什么意思?那就是几乎所有操作发生的地方-保持空间是一个“存储空间”-当数据在那里时,您不能对它做任何事情。无论如何,我已经详细解释N;P;D循环在这里的工作原理,因此不再赘述。这里的区别是test-检查是否替换了某些东西-如果测试成功,则我们跳转到脚本的顶部,否则意味着什么都没有替换并P;D执行。让我知道是否仍然不清楚。
don_crissti

3

使用sedfmt

$ sed -e '1n; s/^[[:upper:]]/\n&/' input.txt | fmt
This is one sentence that is broken.

However this is a good one.

And this one is somehow, broken into many.

sed脚本在以大写字母开头的每一行之前插入换行符(输入的第一行除外)。 sed然后将的输出通过管道fmt传递给重新格式化结果的段落。

par如果已安装,也可以使用。这是另一段重新格式化的程序,但功能比强大得多fmt,具有更多的功能和选项。

请注意,每个段落之间将有一个空白行。段落之间至少用一个空白行隔开。没有空白行,您的整个输入样本将重新格式化为单个多句段,例如:

$ fmt input.txt
This is one sentence that is broken.  However this is a good one.
And this one is somehow, broken into many.

如果您需要在重新格式化后删除空白行,只需sed再次将其通过管道传输-但这将删除所有空白行,包括原始输入中可能包含的所有空白行。例如

$ sed -e '1n; s/^[[:upper:]]/\n&/' input.txt | fmt | sed -e '/^$/d'
This is one sentence that is broken.
However this is a good one.
And this one is somehow, broken into many.

3

您可以执行此操作的另一种方法是:

perl -lpe '$\ = /\.$/ ? $/ : $"' data

其中:$\=> ORS$/=> IRS= \n$"=space

perl -pe '$_ .= <>, eof or redo if s/[^.]\K\n/ /' data

sed -e '
   :a
      /\.$/!N
      s/\n/ /
   ta
' data

2

Python 3

import re
print(re.sub(r'\n([a-z])', r' \1', open('file.txt').read(), flags=re.MULTILINE))

这与Jeff的答案是相同的正则表达式/替换

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.