2

我想拆分一个字符串(有数字)。在下面的示例中,我想在 k 和 k1 处拆分字符串。

my @array1=("0","23","1","4","65","7");
$k=1;$k1=0;
my $j=join("",@array1);
my @ar=split(/($k|$k1)/,$j);
print join(";",@ar),"\n\n";

输出是;0;23;1;4657

在上面的输出中,额外的分号“;” 正在打印

预期的输出是0;23;1;4657

当我为以下示例尝试上述代码时,输​​出是正确的(0;5;123;4;6):额外的分号不在此处打印。

my @array1=("0","5","1234","6");
$k=5;$k1=4;

我不确定,第一个示例出于什么原因打印额外的分号“;”

有人可以帮助我吗?

4

5 回答 5

2

不同之处在于,当您围绕第一个字符进行拆分时,您会在开头得到一个空值。因此额外的; 在 0 之前(和在 "" 之后)。你会同样发现 ;; 分割两个相邻字符时

所以最简单的解决方法是使用 grep 删除空字符串:

my @ar=split(/($k|$k1)/,$j);
@ar = grep /./, @ar;

这将删除 @ar 中的空字符串。

从更大的角度来看,您可能想看看为什么要加入字符串只是为了将它们分开。你也在一个地方分裂了一个可能出现在另一个地方的数字。就像 $k=1 和 @array1 = (11, 23, 1, 4);

于 2012-11-05T01:15:04.820 回答
1

这是一个非常人为的例子,有很多问题(例如,$k 和 $k1 需要用“my”声明,你应该use strict等等)而且它可能会做一些你不想要的事情。

最重要的是,您看到前导分号的原因是,如果您使用与字符串开头匹配的分隔符进行拆分,则split将为此返回一个空列表元素。

print join ';', split /0/, '0123';
于 2012-11-05T01:15:49.033 回答
1

这段代码中有一些我不知道的有趣行为,其他答案中也没有提到。a on 正则表达式通常会发生的情况split是,您要拆分的字符会从结果中省略。但是,似乎如果您在正则表达式中捕获了括号,则捕获的材料将保留在结果中。

脚本

#!/usr/bin/env perl

use strict;
use warnings;

my @array1 = ("0", "23", "1", "4", "65", "7");
my $j = join("", @array1);
my $k;
my $k1;
my @ar;
print "Join [$j]\n";

$k = 1;
$k1 = 0;
printf "%-25s", "Version 1 /($k|$k1)/:";
@ar = split(/($k|$k1)/, $j);
print "[", join(";", @ar), "]\n";

printf "%-25s", "Version 2 /($k|$k1)/:";
$k = "1";
$k1 = "0";
@ar = split(/($k|$k1)/, $j);
print "[", join(";", @ar), "]\n";

printf "%-25s", "Version 3 /[01]/:";
@ar = split(/[01]/, $j);
print "[", join(";", @ar), "]\n";

printf "%-25s", "Version 4 /(0|1)/:";
@ar = split(/(0|1)/, $j);
print "[", join(";", @ar), "]\n";

printf "%-25s", "Version 5 /0|1/:";
@ar = split(/0|1/, $j);
print "[", join(";", @ar), "]\n";

printf "%-25s", "Version 6 /([46])/:";
@ar = split(/([46])/, $j);
print "[", join(";", @ar), "]\n";

printf "%-25s", "Version 7 /(?:[46])/:";
@ar = split(/(?:[46])/, $j);
print "[", join(";", @ar), "]\n";

输出

Join [02314657]
Version 1 /(1|0)/:       [;0;23;1;4657]
Version 2 /(1|0)/:       [;0;23;1;4657]
Version 3 /[01]/:        [;23;4657]
Version 4 /(0|1)/:       [;0;23;1;4657]
Version 5 /0|1/:         [;23;4657]
Version 6 /([46])/:      [0231;4;;6;57]
Version 7 /(?:[46])/:    [0231;;57]

如您所见,当拆分字符串的正则表达式中存在捕获括号时,将保留(捕获的)拆分字符。当括号丢失或显式非捕获(版本 7)时,不保留拆分字符。

而且,如果您仔细阅读手册,split说明确实包含以下段落:

如果 PATTERN 包含捕获组,则对于每个分隔符,为组捕获的每个子字符串生成一个附加字段(按照指定组的顺序,根据反向引用;如果任何组不匹配,则它捕获undef值而不是子字符串。另外,请注意,只要有分隔符(即,每当发生拆分时),就会产生任何此类附加字段,并且此类附加字段不计入 LIMIT。

接下来是一些例子。

在 Mac OS X 10.7.5 上使用 Perl 5.16.0 进行测试。

于 2012-11-05T02:06:44.813 回答
1

一种选择是使用正则表达式而不是split. 这适用于您显示的两个数据集:

use strict;
use warnings;

my @array1 = ( "0", "23", "1", "4", "65", "7" );
my $k      = 1;
my $k1     = 0;

my $j      = join( '', @array1 );
my @ar = $j =~ /([$k$k1]|[^$k$k1]+)/g;
print join( ";", @ar );

输出:

0;23;1;4657
于 2012-11-05T02:27:49.480 回答
0

Perl 提供了一个非常强大的正则表达式替换结构,在这种情况下不需要执行split-fu 和-fu:join

$string =~ s{(?:$k|$k1)\K}{;}g ;
于 2012-11-05T11:36:42.980 回答