在大文件中替换包含换行符的字符串


16

有谁知道基于非行的工具以某种内存有效的方式“二进制”搜索/替换字符串?也看到这个问题

我有一个+ 2GB的文本文件,我想对其进行处理,类似于此操作:

sed -e 's/>\n/>/g'

这意味着,我想删除a之后出现的所有换行符>,但不能在其他地方删除,以便排除tr -d

此命令(我从类似问题的答案中得到)失败,并带有couldn't re-allocate memory

sed --unbuffered ':a;N;$!ba;s/>\n/>/g'

那么,还有其他方法不求助于C吗?我讨厌perl,但愿意在这种情况下例外:-)

我不确定数据中是否会出现任何字符,因此\n,如果可能的话,我想避免用另一个字符临时替换。

有什么好主意吗?


您尝试过选项--unbuffered吗?
ctrl-alt-delor 2014年

有或没有--unbuffered内存用完
MattBianco 2014年

怎么$!办?
ctrl-alt-delor 2014年

第一个sed命令出了什么问题。第二个似乎正在将所有内容读入模式空间,但我不知道那$!是什么。我预计这将需要很多内存。
ctrl-alt-delor 2014年

问题是sed将所有内容读取为行,这就是第一个命令不删除换行符的原因,因为它再次逐行输出文本。第二个命令只是一种解决方法。我认为sed在这种情况下不是合适的工具。
MattBianco 2014年

Answers:


14

在Perl中,这确实是微不足道的,您不应该讨厌它!

perl -i.bak -pe 's/>\n/>/' file

说明

  • -i:在适当位置编辑文件,并创建名为的原始文件的备份file.bak。如果您不想备份,请perl -i -pe改用。
  • -pe:逐行读取输入文件,并应用给出的脚本后打印每一行-e
  • s/>\n/>/:替代,就像sed

这是一种awk方法:

awk  '{if(/>$/){printf "%s",$0}else{print}}' file2 

3
+1。awk golf:awk '{ORS=/>$/?"":"\n"}1'
glenn jackman 2014年

1
为什么我总体上不喜欢perl是与选择该答案(或实际上是您对Gnouc的答案的评论)的原因相同:可读性。与简单的“ sed模式”一起使用perl -pe比复杂的sed表达式更具可读性。
MattBianco 2014年

3
@MattBianco足够公平,但是,正如您所知,这与Perl无关。Gnouc使用的外观是某些正则表达式语言(包括但不限于PCRE)的功能,完全不是Perl的错。另外,':a;N;$!ba;s/>\n/>/g'在您的问题中出现这种sed怪物之后,您就放弃了对可读性的抱怨权!:P
terdon

@glennjackman很好!我正在使用该foo ? bar : baz构造,但无法使其正常工作。
terdon

@terdon:是的,我的错。删除它。
cuonglm 2014年

7

一个perl解决方案:

$ perl -pe 's/(?<=>)\n//'

讲解

  • s/// 用于字符串替换。
  • (?<=>) 是后向模式。
  • \n 匹配换行符。

整个模式意味着删除>前面的所有换行符。


2
关心评论程序的哪些部分吗?我一直在寻找学习。
MattBianco 2014年

2
为什么要打扰后面的人呢?为什么不只是s/>\n/>/呢?
terdon

1
s/>\K\n//也可以使用
glenn jackman 2014年

@terdon:虽然我只是第一件事,但删除而不是替换
cuonglm

@glennjackman:好点!
cuonglm 2014年

3

这个怎么样:

sed ':loop
  />$/ { N
    s/\n//
    b loop
  }' file

对于GNU sed,您还可以尝试根据问题添加-u--unbuffered)选项。GNU sed对此也很满意,因为它很简单:

sed ':loop />$/ { N; s/\n//; b loop }' file

\n如果文件结尾为>\n,则不会删除最后一个,但是无论如何这可能是更好的选择。
斯特凡Chazelas

@StéphaneChazelas,为什么结账}需要使用单独的表达式?这不能用作多行表达式吗?
Graeme 2014年

1
这将在POSIX sed中起作用,带有b loop\n}-e 'b loop' -e '}'不具有b loop;}(当然不是那样)b loop}}并且;在标签名称中有效(尽管在他们的头脑中没有人会使用它。这意味着GNU sed不符合POSIX)并且}需要将命令分开从b命令。
斯特凡Chazelas

@StéphaneChazelas,GNU sed对以上所有内容都满意--posix!对于括号表达式,该标准还具有以下内容- The list of sed functions shall be surrounded by braces and separated by <newline>s。这是否意味着分号只能在大括号之外使用?
Graeme 2014年

@mikeserv,需要循环来处理以结尾的连续行>。斯特凡(Stéphane)指出,原件从未有过。
Graeme 2014年

1

您应该可以使用sedN命令,但是窍门是每次添加另一行时都会从模式空间中删除一行(因此,模式空间始终只包含2条连续的行,而不是尝试整体读取)文件)-试试

sed ':a;$!N;s/>\n/>/;P;D;ba'

编辑:重新阅读彼得·克鲁姆斯的《著名的单线解释》后,我相信更好的sed解决方案是

sed -e :a -e '/>$/N; s/\n//; ta'

>在末尾已经匹配的情况下才追加以下行,并且应该有条件地循环回去以处理连续匹配的行(这是Krumin的39。如果末行以反斜杠结尾,则将其追加到下一行)除了将for替换>\连接字符以及连接字符保留在输出中这一事实外,完全是“ \”


2
如果连续2行结束>(这也是GNU特定的)
不起作用–StéphaneChazelas 2014年

1

sed没有提供没有最终换行符的输出方法。您使用的方法N从根本上是可行的,但是会将不完整的行存储在内存中,因此,如果行太长会失败(sed命令通常不是设计来处理非常长的行)。

您可以改用awk。

awk '{if (/<$/) printf "%s", $0; else print}'

一种替代方法是使用tr换行符替换为“无聊的”频繁出现的字符。在这里可以使用空格-选择一个倾向于出现在数据的每一行或至少大部分行中的字符。

tr ' \n' '\n ' | sed 's/> />/g' | tr '\n ' ' \n'

这两种方法已在此处得到证明,可以在其他答案中更好地发挥作用。如果sed没有2.5G的缓冲区,他的方法将无法正常工作。
mikeserv

有人提到awk吗?哦,我错过了,我只是出于某种原因才在terdon的答案中注意到了perl。没有人提到该tr方法-mikeserv,您发布了另一种恰好也使用的方法(有效,但通用性较低)tr
吉尔(Gilles)'所以

有效,但对我来说听起来不太通用,就像您刚刚将其称为有效且有针对性的解决方案一样。我认为很难说这样的事情没有,这很奇怪,因为它的投票数为0。我自己的解决方案与您更通用的产品之间最大的区别是,我的解决方案专门解决了一个问题,而您的解决方案通常可以解决这可能很值得-我什至可以推翻我的选票-但它们之间的7个小时令人讨厌的事情以及您的回答经常模仿其他人的主题。你能解释一下吗?
mikeserv



-1

有很多方法可以做到这一点,而且大多数方法确实很棒,但是我认为这是我的最爱:

tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'

甚至:

tr '>\n' '\n>' | sed 's/^>*//' | tr '\n>' '>\n'

我根本无法得到您的第一个答案。尽管我欣赏第二个版本的优雅,但我相信您需要删除*。现在,它将删除以结尾的行之后的所有空白行>。嗯 回顾这个问题,我发现它有点模棱两可。这个问题说:“我想删除出现在>... 之后的所有换行符。”我的意思是>\n\n\n\n\nfoo应将其更改为\n\n\n\nfoo,但我想 foo可能是所需的输出。
斯科特(Scott)

@Scott-我对以下各项进行了测试:printf '>\n>\n\n>>\n>\n>>>\n>\nf\n\nff\n>\n' | tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'- >>>>>>>>>>f\n\nff\n\n对我而言,第一个答案是结果。我很好奇,但是您正在做些什么来打破它,因为我想修复它。关于第二点-我不同意它是模棱两可的。该任择议定书没有要求删除所有 > 前面的一个\newline,而是去除所有 \n ewlines 一个>
mikeserv

1
是的,但是有效的解释是,在中>\n\n\n\n\n,只有第一个换行符在>; 之后。所有其他人都在跟随其他换行符。请注意,OP的“如果需要的话,这就是我想要的”建议sed -e 's/>\n/>/g',而不是sed -e 's/>\n*/>/g'
2014年

1
@Scott-这个建议没有用,也永远没有用。我不相信一个不完全理解该代码的人的代码建议可以被视为有效的解释点,因为该人也使用普通语言。除此之外,s/>\n/>/on 的输出(如果确实有效)>\n\n\n\n\n仍然可以s/>\n/>/编辑。
mikeserv
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.