【问题标题】:What does the Perl split function return when there is no value between tokens?当标记之间没有值时,Perl split 函数返回什么?
【发布时间】:2010-10-26 20:59:45
【问题描述】:

我正在尝试使用 split 函数拆分字符串,但标记之间并不总是存在值。

例如:ABC,123,,,,,,XYZ

不过,我不想跳过多个标记。这些值位于字符串中的特定位置。但是,当我进行拆分,然后尝试单步执行生成的数组时,我会收到“使用未初始化的值”警告。

我尝试过使用 $splitvalues[x] eq "" 比较值,也尝试过使用 defined($splitvalues[x]) ,但我终其一生都无法弄清楚如何识别 split 函数在何时将什么放入我的数组中令牌之间没有价值。

这是我的代码的 sn-p(现在有了更脆的好处):

my @matrixDetail = ();

#some other processing happens here that is based on matching data from the 
#@oldDetail array with the first field of the @matrixLine array. If it does
#match, then I do the split
if($IHaveAMatch)
{
    @matrixDetail = split(',', $matrixLine[1]);
}
else
{
    @matrixDetail = ('','','','','','','');
}

my $newDetailString =
  (($matrixDetail[0] eq '') ? $oldDetail[0] : $matrixDetail[0])
. (($matrixDetail[1] eq '') ? $oldDetail[1] : $matrixDetail[1]) 
    .
    .
    .
. (($matrixDetail[6] eq '') ? $oldDetail[6] : $matrixDetail[6]);

因为这只是 sn-ps,所以我省略了一些其他逻辑,但 if 语句位于从技术上返回 @matrixDetail 数组的 sub 内部。如果我在矩阵中找不到匹配项并手动将数组设置为等于空字符串数组,那么我不会收到任何警告。只有当拆分填充@matrixDetail。

另外,我应该提一下,我已经编写代码将近 15 年了,但直到最近我才需要使用 Perl。我的脚本中的逻辑是合理的(或者至少,它有效),我只是在清理我的警告并试图找出这个细微差别。

【问题讨论】:

  • @matrixDetail 或@oldDetail 没有7 个元素,或者@oldDetail 有一些未定义的元素。用 Data::Dumper 找出哪个。如果定义了原始字符串,拆分将返回定义的元素,这只是多少元素的问题。
  • 我的数组中的元素数量不正确似乎是一个常见的主题。但我知道我有正确的数字。正如我所提到的。该脚本有效,无论我是否使用拆分,我都会得到所需的输出。但是,如果我确实使用了拆分,并且我拆分的字符串中有空字段,那么我会收到警告。我想解决警告。
  • 空字符串不会给你未初始化的值警告。您的程序还有其他问题与空字符串或split 返回的值无关。
  • 有没有 stackOverflow 徽章可以证明是个白痴?如果有,我提名我。这是一个数组长度。我正在运行一个循环来设置我的 array = '' 中的任何 undef 值作为额外的预防措施。除了我使用数组长度作为循环计数器。猜猜当最后几个字段在标记之间没有值时发生了什么。我要上交我提到的那几年的经验,以换取一点尊严。

标签: perl split


【解决方案1】:
#!perl

use warnings;
use strict;
use Data::Dumper;

my $str = "ABC,123,,,,,,XYZ";
my @elems = split ',', $str;
print Dumper \@elems;

这给出了:

$VAR1 = [
          'ABC',
          '123',
          '',
          '',
          '',
          '',
          '',
          'XYZ'
        ];

它放入一个空字符串。

编辑:请注意,documentation for split() 声明“默认情况下,保留空的前导字段,并删除空的尾随字段”。因此,如果您的字符串是ABC,123,,,,,,XYZ,,,,,那么您返回的列表将与上面的示例相同,但如果您的字符串是,,,,ABC,123,那么您将有一个列表,其中包含元素0、1和2中的三个空字符串(除了'ABC''123')。

编辑 2: 尝试转储 @matrixDetail@oldDetail 数组。其中一个可能不是您认为的长度。您还可以考虑在尝试使用之前检查这两个列表中的元素数量,以确保您拥有与预期一样多的元素。

【讨论】:

  • 这基本上就是我正在做的,这是我的代码的 sn-p:
  • 显然我不能使用回车键?我会尝试以不同的方式回应。这是我第一次使用 Stack Overflow
  • 您可以编辑您的问题以添加更多信息。在这种情况下,这是最好的方法。 (是的,你不能为 cmets 添加回车)
  • 如果您将所有字段的大小添加到split 或-1,您也会得到尾随的空标记。即,my @elems = split ',', $str, -1; 如果 str 可能是 my $str = ",,ABC,123,,,,,,XYZ,,,"; 否则 'XYZ` 之后的空字段将不会包含在拆分中。
【解决方案2】:

我建议使用来自 CPAN 的Text::CSV。这是一个现成的解决方案,已经涵盖了解析 CSV 格式文件的所有奇怪的边缘情况。

【讨论】:

    【解决方案3】:

    在它们之间没有任何内容的分隔符在拆分时会给出空字符串。在布尔上下文中,空字符串评估为假

    如果您知道您的“详细信息”输入永远不会包含“0”(或其他计算结果为假的标量),那么这应该可以:

    my @matrixDetail = split(',', $matrixLine[1]);
    die if @matrixDetail > @oldDetail;
    
    my $newDetailString = "";
    for my $i (0..$#oldDetail) {
        $newDetailString .= $matrixDetail[$i] || $oldDetail[$i]; # thanks canSpice
    }
    say $newDetailString;
    

    (除了空字符串和零之外,可能还有其他标量评估为假,但我无法将它们命名为我的头顶。)

    TMTOWTDI:

    $matrixDetail[$_] ||= $oldDetail[$_] for 0..$#oldDetail;
    my $newDetailString = join("", @matrixDetail);
    

    编辑:for 循环现在从 0 转到 $#oldDetail 而不是 $#matrixDetail,因为 split 不返回尾随“,,”。

    edit2:如果你不能确定真正的输入不会被评估为假,你总是可以只测试你的分割元素的长度。这当然更安全,尽管可能不那么优雅^_^

    【讨论】:

    • 这将是提及定义或运算符的最佳时机,因为这样您就不必担心空字符串或错误值,而您要检查的只是定义性。
    • @CanSpice 定义了 split 返回的空字符串。
    • 定义了拆分返回的空字符串,这就是为什么当我尝试使用 defined($matrixDetail[$i]) 循环来挑选它们时不起作用的原因。但也不会将它们评估为等同于“”。我真的只需要知道如何识别小虫子。
    【解决方案4】:

    中间的空字段将是''。末尾的空字段将被省略,除非您指定第三个参数来拆分足够大(或全部为 -1)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-08
      • 1970-01-01
      • 2023-01-25
      • 2016-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多