2016-05-30 70 views
9

免责声明:我已经在PerlMonks上交叉发布了此信息。Perl6:用正则表达式在一个字符串中捕获Windows换行符

在Perl5中,我可以快速,方便地打印出结束\r\n Windows的风格路线的十六进制表示:

perl -nE '/([\r\n]{1,2})/; print(unpack("H*",$1))' in.txt 
0d0a 

,如果你想测试在UNIX上创建一个Windows的结尾的文件,创建一个in.txt带有单行和行结尾的文件。然后:perl -ni -e 's/\n/\r\n/g;print' in.txt。 (或在vi/vim中,创建该文件,只需执行:set ff=dos)。

我在Perl6中尝试了很多事情来做同样的事情,但无论我做什么,我都无法使它工作。这是我最近的测试:

use v6; 
use experimental :pack; 

my $fn = 'in.txt'; 

my $fh = open $fn, chomp => False; # I've also tried :bin 
for $fh.lines -> $line { 
    if $line ~~ /(<[\r\n]>**1..2)/ { 
     $0.Str.encode('UTF-8').unpack("H*").say; 
    } 
} 

输出0a,因为这样做:

/(\n)/ 
/(\v)/ 

首先,我甚至不知道如果我使用unpack()或正则表达式正确。其次,如何捕获P6中换行符的两个元素(\r\n)?

+2

在Perl5中,我更喜欢'的sprintf( “%v02X”,$ S)'。适用于任何字符串,而不仅仅是字节串。 – ikegami

回答

5

Perl 6会自动为您关闭行分隔符。这意味着当您尝试进行替换时,它不在那里。

如果有组合字符,Perl 6还会创建合成字符。所以如果您想要输入的基数为16,请使用编码'latin1'或使用返回Buf的$*IN上的方法。


本示例只是将CRLF附加到每行的末尾。
(最后一行将始终与0D 0A结束,即使它没有一个行终止)

perl6 -ne 'BEGIN $*IN.encoding("latin1"); #`(basically ASCII) 
    $_ ~= "\r\n"; #`(append CRLF) 
    put .ords>>.fmt("%02X");' 

你也可以关闭autochomp行为。

perl6 -ne 'BEGIN { 
     $*IN.encoding("latin1"); 
     $*IN.chomp = False; 
    }; 
    s/\n/\r\n/; 
    put .ords>>.fmt("%02X");' 
1

好了,什么我的目标是(我很抱歉,我没有说清楚,当我张贴的问题)是我想读一个文件,捕捉行尾和文件写回使用原始的行结尾(而不是当前平台的结尾)。

我得到了一个概念证明现在工作。我对Perl 6非常陌生,所以代码可能不是很符合p6-ish,但它确实符合我的需要。

代码在FreeBSD上测试:

use v6; 
    use experimental :pack; 

    my $fn = 'in.txt'; 
    my $outfile = 'out.txt'; 

    # write something with a windows line ending to a new file 

    my $fh = open $fn, :w; 
    $fh.print("ab\r\ndef\r\n"); 
    $fh.close; 

    # re-open the file 

    $fh = open $fn, :bin; 

    my $eol_found = False; 
    my Str $recsep = ''; 

    # read one byte at a time, or else we'd have to slurp the whole 
    # file, as I can't find a way to differentiate EOL from EOF 

    while $fh.read(1) -> $buf { 
     my $hex = $buf.unpack("H*"); 
     if $hex ~~ /(0d|0a)/ { 
      $eol_found = True; 
      $recsep = $recsep ~ $hex; 
      next; 
     } 
     if $eol_found { 
      if $hex !~~ /(0d|0a)/ { 
       last; 
      } 
     } 
    } 

    $fh.close; 

    my %recseps = (
     '0d0a' => "\r\n", 
     '0d' => "\r", 
     '0a' => "\n", 
    ); 

    my $nl = %recseps<<$recsep>>; 

    # write a new file with the saved record separator 

    $fh = open $outfile, :w; 
    $fh.print('a' ~ $nl); 
    $fh.close; 

    # re-read file to see if our newline stuck 

    $fh = open $outfile, :bin; 

    my $buf = $fh.read(1000); 
    say $buf; 

输出:

Buf[uint8]:0x<61 0d 0a> 
+0

我会回头介绍介绍/文档,然后在我更熟练后,再次用我的新知识进行测试。 – stevieb

+0

是[newline.t](https://github.com/perl6/roast/S16-io/newline.t)从[烤](https://github.com/perl6/roast/blob/master/README )有帮助吗? – raiph

+0

绝对是!非常感谢你。事实上,我甚至没有想过要看测试文件中的例子,但整个套件将成为一个巨大的学习工具。 – stevieb