最新的方法来删除Perl中的换行符

我正在维护一个脚本,可以从各种来源获得input,并在每行处理它。 取决于实际使用的源代码,换行符可能是Unix风格,Windows风格,或者甚至对于某些聚合input,混合(!)。

当从文件中读取它是这样的:

@lines = <IN>; process(\@lines); ... sub process { @lines = shift; foreach my $line (@{$lines}) { chomp $line; #Handle line by line } } 

所以,我需要做的是将chompreplace为删除Unix风格或Windows风格的换行符。 我正在想办法解决这个问题,Perl的通常的缺点之一:)

你有什么看法,以扼杀通用的线路突破? 什么是最有效的?

编辑:一个小的澄清 – 方法'进程'从某处获取行的列表, 而不是从文件nessecarily读取 。 每一行可能都有

  • 没有追踪的线索
  • Unix风格的换行符
  • Windows风格的线代码
  • 只是回车(当原始数据具有Windows风格的换行符并且用$ / ='\ n'读取时)
  • 线条有不同风格的集合集合

通过perlre文档挖掘了一下, 稍后我会提出我的最好的build议,似乎工作很好。 Perl 5.10添加了\ R字符类作为一个广义的换行符:

 $line =~ s/\R//g; 

这是一样的:

 (?>\x0D\x0A?|[\x0A-\x0C\x85\x{2028}\x{2029}]) 

我会把这个问题持续一段时间,只是为了看看是否有更多漂亮的方法等待build议。

每当我经历input,想要删除或replace字符,我运行它通过像这样的小子程序。

 sub clean { my $text = shift; $text =~ s/\n//g; $text =~ s/\r//g; return $text; } 

这可能不是幻想,但这种方法多年来对我来说一直是无懈可击的。

阅读perlport我build议类似的东西

 $line =~ s/\015?\012?$//; 

无论你在哪个平台上,以及你可能正在处理的换行样式,都是安全的,因为\ r和\ n中的内容可能因不同的Perl风格而有所不同。

从2017年注意:File :: Slurp不build议由于devise错误和未保持的错误。 使用File :: Slurper或Path :: Tiny代替。

延伸你的答案

 use File::Slurp (); my $value = File::Slurp::slurp($filename); $value =~ s/\R*//g; 

File :: Slurp提取文件IO的东西,只是为你返回一个string。

注意

  1. 重要的是要注意添加/g ,如果没有它,给定一个多行string,它只会replace第一个冒犯的字符。

  2. 另外,删除$ ,这对于这个目的来说是多余的,因为我们要删除所有换行符,而不是在这个操作系统上以$表示之前的换行符。

  3. 在多行string中, $匹配string的末尾,这将是有问题的)。

  4. 第3点意味着第2点是假设你也想使用/m否则“$”对于任何一行实际上没有任何实际意义的行,或者在进行单行处理时,是一个操作系统实际上理解$并设法find进行$ \R*

例子

 while( my $line = <$foo> ){ $line =~ $regex; } 

鉴于上述表示法,操作系统不理解您的文件'\ n'或'\ r'分隔符,默认情况下操作系统的默认分隔符设置为$/将导致读取整个文件作为一个连续的string除非你的string中有$ OS的分隔符,那么它将由此分隔)

所以在这种情况下,所有这些正则expression式都是无用的:

  • /\R*$// :只会擦除文件中\R的最后一个序列
  • /\R*// :只会擦除文件中的第一个\R序列
  • /\012?\015?// :何时只会擦除第一个012\015\012\015序列, \015\012会导致\012\015被发射。

  • /\R*$// :如果在文件中碰巧没有'\ 015 $ OSDELIMITER'的字节序列,那么除了操作系统自己的以外, 没有换行符将被删除。

它似乎没有人得到我在说什么,所以这里是示例代码,这是testing 删除换行。 运行它,你会发现它留下了换行符。

 #!/usr/bin/perl use strict; use warnings; my $fn = 'TestFile.txt'; my $LF = "\012"; my $CR = "\015"; my $UnixNL = $LF; my $DOSNL = $CR . $LF; my $MacNL = $CR; sub generate { my $filename = shift; my $lineDelimiter = shift; open my $fh, '>', $filename; for ( 0 .. 10 ) { print $fh "{0}"; print $fh join "", map { chr( int( rand(26) + 60 ) ) } 0 .. 20; print $fh "{1}"; print $fh $lineDelimiter->(); print $fh "{2}"; } close $fh; } sub parse { my $filename = shift; my $osDelimiter = shift; my $message = shift; print "Parsing $message File $filename : \n"; local $/ = $osDelimiter; open my $fh, '<', $filename; while ( my $line = <$fh> ) { $line =~ s/\R*$//; print ">|" . $line . "|<"; } print "Done.\n\n"; } my @all = ( $DOSNL,$MacNL,$UnixNL); generate 'Windows.txt' , sub { $DOSNL }; generate 'Mac.txt' , sub { $MacNL }; generate 'Unix.txt', sub { $UnixNL }; generate 'Mixed.txt', sub { return @all[ int(rand(2)) ]; }; for my $os ( ["$MacNL", "On Mac"], ["$DOSNL", "On Windows"], ["$UnixNL", "On Unix"]){ for ( qw( Windows Mac Unix Mixed ) ){ parse $_ . ".txt", @{ $os }; } } 

对于CLEARLY未处理的输出,请参见: http : //pastebin.com/f2c063d74

请注意,当然有一定的组合,但他们可能是你自己经过testing的。

请注意,在此输出中,所有结果都必须是>|$string|<>|$string|<NO LINE FEEDS被视为有效输出。

$string的forms为{0}$data{1}$delimiter{2} ,其中在所有输出源中,应该是:

  1. {1}{2}之间没有任何内容
  2. 只有|<>|{1}{2}
 $line =~ s/[\r\n]+//g; 

在你的例子中,你可以去:

 chomp(@lines); 

要么:

 $_=join("", @lines); s/[\r\n]+//g; 

要么:

 @lines = split /[\r\n]+/, join("", @lines); 

直接在文件上使用这些:

 perl -e '$_=join("",<>); s/[\r\n]+//g; print' <a.txt |less perl -e 'chomp(@a=<>);print @a' <a.txt |less 

为了扩展Ted Cambron的回答,以及这里没有提到的东西:如果你从一段input的文本中不加区分地删除所有换行符,那么当你稍后输出文本时,最后会有段落相互之间没有空格。 这是我使用的:

 sub cleanLines{ my $text = shift; $text =~ s/\r/ /; #replace \r with space $text =~ s/\n/ /; #replace \n with space $text =~ s/ / /g; #replace double-spaces with single space return $text; } 

最后一个replace使用g'贪婪'修饰符,所以它继续find双空格,直到它们全部replace它们。 (有效地替代更多的单一空间)