Perl6:使用正则表达式捕获字符串中的Windows换行符

问题描述 投票:9回答:2

免责声明:我在PerlMonks上交叉发布了此消息。

在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)?

regex perl6 raku
2个回答
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>
© www.soinside.com 2019 - 2024. All rights reserved.