【问题标题】:Splitting a string which contains numerical digits in Perl在 Perl 中拆分包含数字的字符串
【发布时间】:2012-11-05 01:00:36
【问题描述】:

我想拆分一个字符串(有数字)。在下面的示例中,我想在 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;

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

有人可以帮助我吗?

【问题讨论】:

  • 什么是非数字?我想人们手上有什么......
  • 一般来说,如果你发现自己在执行split,然后是join,你应该使用s///g

标签: perl split


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 当我为这个字符串尝试你的代码时 $j= "0,2,3,6,5,1,4,7,8,12,11,10,9" for $k= 1 和 $k1=0,拆分在 1 和 0 处未正确发生。您拆分命令还考虑了 10 和 11 中的 1 和 0。您能帮我吗?
  • 预期结果:0;2,3,6,5;1;4,7,8,12,11,10,9 您的代码结果:0;,2,3,6,5 ,;1;,4,7,8,;1;2,;1;1;,;1;0;,9
【解决方案2】:

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

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

print join ';', split /0/, '0123';

【讨论】:

    【解决方案3】:

    这段代码中有一些我不知道的有趣行为,其他答案中也没有提到。在正则表达式上使用 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 包含 capturing groups,则对于每个分隔符,为组捕获的每个子字符串生成一个附加字段(按照指定组的顺序,按照 backreferences;如果任何组不匹配,然后它捕获undef 值而不是子字符串。此外,请注意,只要有分隔符(即,每当发生拆分),就会生成任何此类附加字段,并且此类附加字段不计入限制。

    接下来是一些例子。

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

    【讨论】:

      【解决方案4】:

      一种选择是使用正则表达式而不是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
      

      【讨论】:

        【解决方案5】:

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

        $string =~ s{(?:$k|$k1)\K}{;}g ;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-13
          • 1970-01-01
          • 1970-01-01
          • 2013-11-08
          • 2023-03-14
          • 1970-01-01
          • 2019-06-03
          • 2013-07-07
          相关资源
          最近更新 更多