用新线分割很长(4GB)的字符串

时间:2017-06-28 19:34:30

标签: bash perl sed

我有一个应该是JSON对象的文件,每行一个。不幸的是,在创建文件时发生了错误的通信,而JSON对象之间只有一个空格,而不是换行符。

我需要通过用} {替换}\n{的每个实例来解决此问题。

sed或Perl应该很容易,对吧?

sed -e "s/}\s{/}\n{/g" file.in > file.out

perl -pe "s/}\s{/}\n{/g" file.in > file.out

但是file.in实际上是4.4 GB,这似乎导致了这两种解决方案的问题。

sed命令以中途正确的文件结束,但file.out只有335 MB,只是输入文件的前1/10左右,在一行中间切断。它几乎就像sed刚刚在流中间退出。也许它试图将整个4.4 GB的文件加载到内存中,但是耗尽大约300MB的堆栈空间并且无声地自杀。

Perl命令错误,显示以下消息:

[1] 2904 segmentation fault perl -pe "s/}\s{/}\n{/g" file.in > file.out

我还应该尝试什么?

5 个答案:

答案 0 :(得分:4)

与早期的解决方案不同,此解决方案处理{"x":"} {"}

use strict;
use warnings;
use feature qw( say );

use JSON::XS qw( );

use constant READ_SIZE => 64*1024*1024;

my $j_in = JSON::XS->new->utf8;
my $j_out = JSON::XS->new;

binmode STDIN;
binmode STDOUT, ':encoding(UTF-8)';

while (1) {
   my $rv = sysread(\*STDIN, my $block, READ_SIZE);
   die($!) if !defined($rv);
   last if !$rv;

   $j_in->incr_parse($block);

   while (my $o = $j_in->incr_parse()) {
      say $j_out->encode($o);
   }
}

die("Bad data") if $j_in->incr_text !~ /^\s*\z/;

答案 1 :(得分:1)

perl -ple 'BEGIN{$/=qq/} {/;$\=qq/}\n{/}undef$\ if eof' <input >output

答案 2 :(得分:1)

Perl中的默认输入记录分隔符是\n,但您可以将其更改为您想要的任何字符。对于此问题,您可以使用{(八进制173)。

perl -0173 -pe 's/}\s{/}\n{/g' file.in > file.out

答案 3 :(得分:0)

您可以以块/块的形式读取输入并逐个处理。

use strict;
use warnings;

binmode(STDIN);
binmode(STDOUT);
my $CHUNK=0x2000; # 8kiB
my $buffer = '';

while( sysread(STDIN, $buffer, $CHUNK, length($buffer))) {
  $buffer =~ s/\}\s\{/}\n{/sg;
  if( length($buffer) > $CHUNK) { # More than one chunk buffered
    syswrite( STDOUT, $buffer, $CHUNK); # write  FIRST of buffered chunks
    substr($buffer,0,$CHUNK,''); # remove FIRST of buffered chunks from buffer
  }
}
syswrite( STDOUT, $buffer) if length($buffer);                                             

答案 4 :(得分:0)

假设您的输入在其他不需要替换的上下文中不包含import matplotlib.pyplot as plt x = [0.00001,0.001,0.01,0.1,0.5,1,5] y = [0.945,0.885,0.893,0.9,0.996,1.25,1.19] plt.xlim(0.00001,5) plt.ylim(0.8,1.4) plt.plot(x, y, marker='o', linestyle='--', color='r', label='Square') plt.xlabel('x') plt.ylabel('y') plt.title('compare') plt.legend() plt.show() 对,那么您需要的是:

} {

e.g。

awk -v RS='} {' '{ORS=(RT ? "}\n{" : "\n")} 1'

以上使用GNU awk进行多字符RS和RT,并且可以在任何大小的输入文件上工作,因为它不会一次将整个文件读入内存,只有每个$ printf '{foo} {bar}' | awk -v RS='} {' '{ORS=(RT ? "}\n{" : "\n")} 1' {foo} {bar} - 分开的“行”一个一次。