在perl中,为什么在模式上分割字符串会在某些分裂点处产生空字符

时间:2017-06-16 10:30:27

标签: regex perl split

假设我有一个字符串如下:

my $line="(l_extendedprice*(1-l_discount)*(1+l_tax))";

我希望在获得非单词字符时拆分此字符串,并且我还想记住该字符。这是我的代码:

my @split_on_non_word=split /(\W)/,$line;
print scalar @split_on_non_word, "\n";
print "split:$_\n" for @split_on_non_word;

以下是我的输出:

20
split:
split:(
split:l_extendedprice
split:*
split:
split:(
split:1
split:-
split:l_discount
split:)
split:
split:*
split:
split:(
split:1
split:+
split:l_tax
split:)
split:
split:)

问题是,我在我的数组中获得了无效的字符,例如(,*。我感觉它可能与元字符有关。但是,当分裂时,它不会插入任何空字符" +"这也是一个元字符。在这方面有任何帮助非常感谢。

当然,有一些方法来处理数组并摆脱空字符,这是我现在的解决方法。但是,我只是在寻找更好的解决方案。

预期输出:

15
split:(
split:l_extendedprice
split:*
split:(
split:1
split:-
split:l_discount
split:)
split:*
split:(
split:1
split:+
split:l_tax
split:)
split:)

4 个答案:

答案 0 :(得分:7)

split()可能不是获得预期结果的最佳方式,您可以使用正则表达式,

use Data::Dumper;

my $line="(l_extendedprice*(1-l_discount)*(1+l_tax))";
my @split_on_non_word = $line =~ /(\w+|\W)/g;

print Dumper \@split_on_non_word;

输出

$VAR1 = [
      '(',
      'l_extendedprice',
      '*',
      '(',
      '1',
      '-',
      'l_discount',
      ')',
      '*',
      '(',
      '1',
      '+',
      'l_tax',
      ')',
      ')'
    ];

答案 1 :(得分:3)

另一种方式:

以分割模式捕获的内容很少与某些任务完全相同。如果没有,您要么必须对结果进行后处理,要么使用匹配而不是拆分,要么尝试使用非捕获拆分模式来执行您想要的操作。其他答案采用前两种方法之一。对于第三个,你想要在任何一方都有非单词字符的地方进行拆分,这很容易:

split /(?<=\W)|(?=\W)/

答案 2 :(得分:2)

您已将每个\W字符声明为字段分隔符。字符串的第一个字符是(。这意味着它必须将空字符串与后面的字符串分开。

然后你有*(:两个分隔符的序列。这意味着,它们之间必须有一个空字段。

对于1+l_tax,显然,分隔符的任意一侧都有非空字符串+

对我来说,过滤掉空字段似乎最简单:

#!/usr/bin/env perl

use strict;
use warnings;

use YAML::XS;

my $line = "(l_extendedprice*(1-l_discount)*(1+l_tax))";

my $tokens = [ grep length, (split /(\W)/, $line) ];

print scalar @$tokens, "\n";

print Dump $tokens;

输出:

15
---
- (
- l_extendedprice
- '*'
- (
- '1'
- '-'
- l_discount
- )
- '*'
- (
- '1'
- +
- l_tax
- )
- )

答案 3 :(得分:1)

您可以将单词边界\b\W的检查结合起来,在这种情况下,您可以拆分空字符串,只需将字符串转换为字符列表。

my $line="(l_extendedprice*(1-l_discount)*(1+l_tax))";

my @split_on_non_word = map { /\W/ ? split '', $_ : $_ } split /\b/,$line;
print scalar @split_on_non_word, "\n";
print "split:$_\n" for @split_on_non_word;

输出:

15
split:(
split:l_extendedprice
split:*
split:(
split:1
split:-
split:l_discount
split:)
split:*
split:(
split:1
split:+
split:l_tax
split:)
split:)