【问题标题】:In Perl, substitution operator for removing space is removing value 0 when removing space在 Perl 中,用于删除空间的替换运算符在删除空间时删除值 0
【发布时间】:2017-12-01 12:01:22
【问题描述】:

我们有代码,其中输入可以是单个值或逗号分隔值。我们需要删除每个值前后存在的所有空格。

我们的做法如下:

my @var_1 = split /,/,$var;
print "print_1 : @var_1 \n ";
@var_1 = grep {s/^\s+|\s+$//g; $_ } @var_1;
print "print_2 : @var_1 \n ";

$var 将包含输入值。如果 $var 为 0 ,则 print_1 打印值 0 但 print_2 不打印任何内容。我们的要求只是删除值 0 之前和之后的空格。但是如果 $var 为 1,则 print(print_1 和 print_2)都正确打印值 1。如果我们将输入作为 1,0,它将删除 0 并打印值 1在 print_2 中。

我不确定它为什么要删除值 0。是否可以对替换运算符进行任何更正以不删除值 0 ?

提前致谢!!!

【问题讨论】:

  • 我认为您想使用map,而不是grep,但请参阅我的答案,以获得更简单的方法,完全避免map/grep
  • 如果您想改进您的 Perl,请将您的完整程序发布到 Code Review。如果你愿意,我有几句话要给你。

标签: perl


【解决方案1】:

在 Perl 中,只有少数不同的值是 false。这些主要是

  • undef
  • 整数0
  • 无符号整数0
  • 浮点数0
  • 字符串0
  • 空字符串""

这里有空字符串变体和0

@var_1 = grep {s/^\s+|\s+$//g; $_ } @var_1;

这段代码可以分为三种方式:

  • $_ 被清理并变为 foo。我们希望它通过。
  • $_ 被清理并变成0。我们希望它通过。
  • $_ 被清理并成为空字符串""。我们希望它失败。

但是发生的情况是因为0 是假的,而grep 只有在其块中的最后一条语句为真时才允许它通过。这就是我们想要的空字符串"",但不是0

@var_1 = grep {s/^\s+|\s+$//g; $_ ne "" } @var_1;

现在我们明确检查清理后的值不是空字符串"",允许零0

这是一个完整版本,其中包含已清理的变量名称(命名很重要!)。

my $input = q{foo, bar, 1 23   ,,0};
my @values = split /,/,$input;
print "print_1 : @values \n ";
@values = grep {s/^\s+|\s+$//g; $_ ne q{} } @values;
print "print_2 : @values \n ";

输出是:

print_1 : foo  bar  1 23     0 
print_2 : foo bar 1 23 0 

请注意,您的grep 不是最佳解决方案。一如既往,there is more than one way to do it 在 Perl 中。 Сухой27 suggests in their answerfor 循环更简洁,我会使用它。

【讨论】:

  • 有趣的是,grep {s/^\s+|\s+$//g } @var_1; 也应该可以工作,因为 $_ 有别名,但严重掩盖了意图。
  • @Сухой27 是的。我相信使用grep 改变价值的整个想法已经存在根本性的缺陷。我在第三次阅读时才注意到这一点。你的干净得多
  • s///r 来救援。 :)
【解决方案2】:

如果您想以逗号分隔并从每个结果字符串中删除前导和尾随空格,这可以从字面上翻译成代码:

my @var = map s/^\s+|\s+\z//gr, split /,/, $var, -1;

/r 使s/// 返回替换的结果(需要 perl 5.14+)。拆分时需要-1,以防止它忽略尾随的空字段。

如果没有零长度条目(所以不是例如a,,b),您可以直接从字符串中提取您想要的内容(不以空格开头或结尾的非逗号序列)而不是首先拆分它:

@var = $var =~ /(?!\s)[^,]+(?<!\s)/g;

【讨论】:

  • @simbabque 一个挑战:看看你能不能想出一个@var = $var =~ /.../g 的答案来保留空白字段;我放弃了。
  • 没有删除交易的那些部分吗?
  • @simbabque 我看到你是这么认为的;除了可能首先使用 grep 之外,我没有看到任何表明这一点的东西。我觉得不够权威
  • 我明白你的意思。嗯。我会玩。
  • 也请@CasimiretHippolyte 来看看。
【解决方案3】:

你想要

@var_1 = map { my $v = s/^\s+|\s+$//gr; length($v) ? $v : () } @var_1

而不是,

@var_1 = grep {s/^\s+|\s+$//g; $_ } @var_1;

grep用于过滤列表元素,过滤掉所有的false值(包括''0undef

【讨论】:

  • 这不会从数组中删除空(仅限空格)字符串。目前尚不清楚 OP 是否想要这种行为。
  • 它遵循 OP prog。逻辑并回答问题,why 0 is filtered out
  • 我是说他们可能打算@var_1 = grep { s/^\s+|\s+$//g; length $_ } @var_1
【解决方案4】:

我建议使用从第一个到最后一个非空格字符匹配的正则表达式模式使用 map 清理数组

也不需要单独做split操作

这样

my @var_1 = map { / ( \S (?: .* \S )? ) /x } split /,/, $var;

请注意,此方法会删除空字段。目前尚不清楚是否需要这样做

【讨论】:

    【解决方案5】:

    你也可以使用

    @values = map {$_ =~ s/^\s+|\s+$//gr } @values;
    

    甚至更简洁

    @values = map {s/^\s+|\s+$//gr } @values;
    

    删除数组中的空格

    不要忘记r,因为它是非破坏性选项,否则您将用空格出现的次数替换字符串。

    这表示它只有在您使用 Perl 5.14 或更高版本时才有效, 这里有一些文档;) https://www.perl.com/pub/2011/05/new-features-of-perl-514-non-destructive-substitution.html

    我认为这种合成器更容易理解,因为它更接近于“通常”的替换方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-21
      • 1970-01-01
      • 2018-01-19
      • 2019-08-25
      • 1970-01-01
      • 2023-03-15
      • 2012-10-20
      • 2020-11-19
      相关资源
      最近更新 更多