Perl6:使用正则表达式在字符串中捕获 Windows 换行符
Perl6: Capturing Windows newline in a string with regex
免责声明:我已经在 PerlMonks 上交叉发布了这篇文章。
在 Perl5 中,我可以快速轻松地打印出 \r\n
Windows 样式行结尾的十六进制表示:
perl -nE '/([\r\n]{1,2})/; print(unpack("H*",))' 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)/ {
[=12=].Str.encode('UTF-8').unpack("H*").say;
}
}
输出 0a
,如:
/(\n)/
/(\v)/
首先,我什至不知道我是否正确使用了 unpack()
或正则表达式。其次,如何捕获 P6 中换行符的两个元素 (\r\n
)?
Perl 6 会自动为您去掉行分隔符。这意味着当您尝试进行替换时它不存在。
如果有组合字符,Perl 6 也会创建合成字符。因此,如果您想要输入的 16 进制表示,请使用编码 'latin1'
或在 $*IN
上使用 return Buf.
上的方法
此示例只是将 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");'
好的,所以我的目标是(很抱歉我在发布问题时没有说清楚)是我想读取一个文件,捕获行尾,然后使用原始行结尾(而不是当前平台的结尾)。
我现在得到了一个概念证明。我是 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>
免责声明:我已经在 PerlMonks 上交叉发布了这篇文章。
在 Perl5 中,我可以快速轻松地打印出 \r\n
Windows 样式行结尾的十六进制表示:
perl -nE '/([\r\n]{1,2})/; print(unpack("H*",))' 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)/ {
[=12=].Str.encode('UTF-8').unpack("H*").say;
}
}
输出 0a
,如:
/(\n)/
/(\v)/
首先,我什至不知道我是否正确使用了 unpack()
或正则表达式。其次,如何捕获 P6 中换行符的两个元素 (\r\n
)?
Perl 6 会自动为您去掉行分隔符。这意味着当您尝试进行替换时它不存在。
如果有组合字符,Perl 6 也会创建合成字符。因此,如果您想要输入的 16 进制表示,请使用编码 'latin1'
或在 $*IN
上使用 return Buf.
此示例只是将 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");'
好的,所以我的目标是(很抱歉我在发布问题时没有说清楚)是我想读取一个文件,捕获行尾,然后使用原始行结尾(而不是当前平台的结尾)。
我现在得到了一个概念证明。我是 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>