如何计算以下字符串中空“字段”的数量?空字段由-|
or|-|
或表示|-
我编写的正则表达式似乎正在工作,除非我有连续的空字段?我如何使它不那么贪婪?
my $string = 'P|CHNA|string-string|-|-|25.75|-|2562000|-0.06';
my $count = () = ($string=~/(?:^-\||\|-$|\|-\|)/g);
printf("$count\n");
上面的代码打印 2 而不是我想要的 3。
为此,我将完全避免使用正则表达式路线,而是将其视为列表,因为它是一个:
my $count = grep { /^-$/ } split /\|/, $string;
这个问题实际上与贪婪/懒惰没有任何关系(这只适用于*
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的支持。我仍然认为分裂|
不过,这是解决这个问题的最佳方法。)
诀窍是使用环视。有人的第一次尝试可能如下:
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;