你可以挽救我的负面观察背后的例子来传递数字吗?

时间:2010-02-24 23:22:16

标签: regex perl lookbehind

Mastering Perl的“高级正则表达式”一章中,我有一个破碎的例子,我无法找到一个很好的修复。这个例子可能是为了自己的利益而过于聪明,但也许有人可以为我解决它。可能有一本书的免费副本用于工作修复。 :)

在讨论外观的部分中,我想使用负面的lookbehind来实现具有小数部分的数字的通用例程。关键是要使用负面的后视,因为那是主题。

我愚蠢地这样做了:

$_ = '$1234.5678';
s/(?<!\.\d)(?<=\d)(?=(?:\d\d\d)+\b)/,/g;  # $1,234.5678

(?<!\.\d)断言(?=(?:\d\d\d)+\b)之前的位不是小数点和数字。

愚蠢的事情并不是在努力打破它。通过在末尾添加另一个数字,现在有一组三个数字,前面没有小数点和数字:

$_ = '$1234.56789';
s/(?<!\.\d)(?<=\d)(?=(?:\d\d\d)+\b)/,/g;  # $1,234.56,789

如果在Perl中lookbehinds可以是可变宽度,那么这将非常简单。但他们不能。

请注意,在没有负面后观的情况下很容易做到这一点,但这不是示例的重点。有没有办法挽救这个例子?

3 个答案:

答案 0 :(得分:14)

如果没有某种形式的可变宽度后视镜,我认为这是不可能的。在5.10中添加\K断言提供了一种伪装可变宽度正向后视的方法。我们真正需要的是可变宽度负面后视,但是有一点点创造力和很多丑陋我们可以让它起作用:

use 5.010;
$_ = '$1234567890.123456789';
s/(?<!\.)(?:\b|\G)\d+?\K(?=(?:\d\d\d)+\b)/,/g;
say;  # $1,234,567,890.123456789

如果有一种模式要求/x符号,那就是这个:

s/
  (?<!\.)        # Negative look-behind assertion; we don't want to match
                 # digits that come after the decimal point.

  (?:            # Begin a non-capturing group; the contents anchor the \d
                 # which follows so that the assertion above is applied at
                 # the correct position.

    \b           # Either a word boundary (the beginning of the number)...

    |            # or (because \b won't match at subsequent positions where
                 # a comma should go)...

    \G           # the position where the previous match left off.

  )              # End anchor grouping

  \d+?           # One or more digits, non-greedily so the match proceeds
                 # from left to right. A greedy match would proceed from
                 # right to left, the \G above wouldn't work, and only the
                 # rightmost comma would get placed.

  \K             # Keep the preceding stuff; used to fake variable-width
                 # look-behind

                 # <- This is what we match! (i.e. a position, no text)

  (?=            # Begin a positive look-ahead assertion

    (?:\d\d\d)+  # A multiple of three digits (3, 6, 9, etc.)

    \b           # A word (digit) boundary to anchor the triples at the
                 # end of the number.

  )              # End positive look-ahead assertion.
/,/xg;

答案 1 :(得分:4)

如果必须在Stack Overflow上发帖,询问是否有人可以通过负面观察来弄清楚如何做到这一点,那么它显然不是负面观察的好例子。你最好想出一个新的例子,而不是试图挽救这个例子。

本着这种精神,自动拼写纠正器怎么样?

s/(?<![Cc])ei/ie/g; # Put I before E except after C

(显然,这不是英语中的硬性规则,但我认为这是负面观察的更现实的应用。)

答案 2 :(得分:0)

我不认为这就是你所追求的(特别是因为负面的后置断言已被删除),但我想,你唯一的选择就是像这个例子那样捏起小数位:

s/
  (?:
    (?<=\d)
    (?=(?:\d\d\d)+\b)
   |
    ( \d{0,3} \. \d+ )
  )
 / $1 ? $1 : ',' /exg;

P.S。我认为这是一个很好的例子,因为它没有被用作书中的第一个,因为它展示了一些观察断言的缺陷和限制。