6

如何计算以下字符串中空“字段”的数量?空字段由-|or|-|或表示|- 我编写的正则表达式似乎正在工作,除非我有连续的空字段?我如何使它不那么贪婪?

my $string = 'P|CHNA|string-string|-|-|25.75|-|2562000|-0.06';
my $count = () = ($string=~/(?:^-\||\|-$|\|-\|)/g);   
printf("$count\n");

上面的代码打印 2 而不是我想要的 3。

4

3 回答 3

7

为此,我将完全避免使用正则表达式路线,而是将其视为列表,因为它是一个:

my $count = grep { /^-$/ } split /\|/, $string;
于 2013-10-16T21:21:03.067 回答
3

这个问题实际上与贪婪/懒惰没有任何关系(这只适用于*or之类的重复运算符+)。

问题是紧挨着的两个空字段:|-|-|. 第一个正在匹配,但第二个失败,因为开口|已经被消耗,但是因为你在 rule 中有 beining-of-line 标记^-|,它与那个不匹配。

我认为更简单的方法是将您的输入拆分|,然后查找仅包含 a 的任何字段-

my $count = 0;
foreach (split(/\|/,$string)) { if( /^-$/ ) { $count++; } }

由于 Perl 不支持可变长度的lookbehinds(至少据我所知),因此实际上没有办法使用正则表达式来稳健地实现这一点。“作弊”的一种方法是|在开头和结尾附加 a ,然后您可以成功使用lookbehind/lookahead断言:

$string = "|$string|";
my $count = () = $string=~/(?<=\|)-(?=\|)/g;

(下面ikegama的答案有一个替代解决方案,它确实使用非变量环视断言而不修改字符串,所以当我说“没有办法用正则表达式实现这个”时我错了。对ikegama的支持。我仍然认为分裂|不过,这是解决这个问题的最佳方法。)

于 2013-10-16T21:14:19.463 回答
2

诀窍是使用环视。有人的第一次尝试可能如下:

my $count = () = $string =~ /
   (?<\|)  # Preceded by "|"
   (-)
   (?=\|)  # Followed by "|"
/xg;

但这不起作用。上面的问题是它没有检测到第一个字段或最后一个字段是否为空。解决这个问题的两种方法:

my $count = () = "|$string|" =~ /
   (?<\|)  # Preceded by "|"
   (-)
   (?=\|)  # Followed by "|"
/xg;

或者

my $count = () = $string =~ /
   (?<![^|])  # Not preceded by a char other than "|"
   (-)
   (?![^|])   # Not followed by a char other than "|"
/xg;
于 2013-10-16T21:27:11.297 回答