将字符串拆分为固定长度的块并在 Raku 中写在单独的行中

Split string to fixed length chunks and write in separate line in Raku

我有一个文件test.txt:

Stringsplittingskills

我想读取这个文件并写入另一个文件out.txt,每行三个字符,如

Str
ing
spl
itt
ing
ski
lls

我做了什么

my $string = "test.txt".IO.slurp;
my $start = 0;
my $elements = $string.chars;
# open file in writing mode
my $file_handle = "out.txt".IO.open: :w;
while $start < $elements {
    my $line = $string.substr($start,3);
    if $line.chars == 3 {
        $file_handle.print("$line\n") 
    } elsif $line.chars < 3 {
        $file_handle.print("$line")
    }      
    $start = $start + 3;
}
# close file handle
$file_handle.close

当字符串的长度不是 3 的倍数时,这运行良好。当字符串长度是 3 的倍数时,它会在输出文件的末尾插入 extra newline。当字符串长度是 3 的倍数时,如何避免在末尾插入新行?

我尝试了另一种更短的方法,

my $string = "test.txt".IO.slurp;

my $file_handle = "out.txt".IO.open: :w;
for $string.comb(3) -> $line {
    $file_handle.print("$line\n")
}

仍然遇到同样的问题。

找了here, here还是没能解决。

spurt "out.txt", "test.txt".IO.comb(3).join("\n")

正确答案当然是使用.comb.join

也就是说,这就是您修复代码的方法。


您可以更改 if 行以检查它是否在末尾,并使用 else.

if $start+3 < $elements {
    $file_handle.print("$line\n") 
} else {
    $file_handle.print($line)
}

我个人会更改它,以便只有添加 \n 是有条件的。

while $start < $elements {
    my $line = $string.substr($start,3);
    $file_handle.print( $line ~ ( "\n" x ($start+3 < $elements) ));
    $start += 3;
}

这是有效的,因为 < returns TrueFalse

True == 1False == 0 以来,x 运算符最多重复一次 \n

'abc' x 1;     # 'abc'
'abc' x True;  # 'abc'

'abc' x 0;     # ''
'abc' x False; # ''

如果您非常谨慎,可以使用 x+?
(实际上是 3 个独立的运算符。)

'abc' x   3; # 'abcabcabc'
'abc' x+? 3; # 'abc'

infix:« x »( 'abc', prefix:« + »( prefix:« ? »( 3 ) ) );

如果我要这样构建它,我可能会使用 loop

loop ( my $start = 0; $start < $elements ; $start += 3 ) {
    my $line = $string.substr($start,3);
    $file_handle.print( $line ~ ( "\n" x ($start+3 < $elements) ));
}

或者不是在每行的末尾添加换行符,而是将其添加到除第一行以外的每一行的开头。

while $start < $elements {
    my $line = $string.substr($start,3);

    my $nl = "\n";

    # clear $nl the first time through
    once $nl = "";

    $file_handle.print($nl ~ $line);

    $start = $start + 3;
}

另一种方法使用 substr-rw

subset PositiveInt of Int where * > 0;

sub break( Str $str is copy, PositiveInt $length )
{
    my $i = $length;

    while $i < $str.chars
    {
        $str.substr-rw( $i, 0 ) = "\n";
        $i += $length + 1;
    }

    $str;
}

say break("12345678", 3);

输出

123
456
78

在命令行提示下,下面三个一行的解决方法。

使用 combbatch(在末尾保留不完整的 3 个字母):

~$ echo 'StringsplittingskillsX' | perl6 -ne '.join.put for .comb.batch(3);'
Str
ing
spl
itt
ing
ski
lls
X

简化(没有batch,只有comb):

~$ echo 'StringsplittingskillsX' | perl6 -ne '.put for .comb(3);'
Str
ing
spl
itt
ing
ski
lls
X

或者,使用 combrotor(丢弃末尾不完整的 3 个字母):

~$ echo 'StringsplittingskillsX' | perl6 -ne '.join.put for .comb.rotor(3);'
Str
ing
spl
itt
ing
ski
lls