Можете ли вы спасти мой негативный взгляд на пример для обобщения чисел? - PullRequest
17 голосов
/ 25 февраля 2010

В главе «Расширенное регулярное выражение» в Освоение Perl у меня есть неработающий пример, для которого я не могу найти хорошее исправление. Возможно, пример пытается быть слишком умным для своего блага, но, возможно, кто-то может это исправить для меня. В ней может быть бесплатная копия книги для исправлений. :)

В разделе, посвященном поиску обходных путей, я хотел использовать отрицательный взгляд назад для реализации подпрограммы-компилятора для чисел с дробными порциями. Смысл в том, чтобы использовать отрицательный взгляд назад, потому что это была тема.

Я тупо сделал это:

$_ = '$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

Если бы lookbehinds мог иметь переменную ширину в Perl, это было бы действительно легко. Но они не могут.

Обратите внимание, что это легко сделать без негативного взгляда, но дело не в этом. Есть ли способ спасти этот пример?

Ответы [ 3 ]

14 голосов
/ 26 февраля 2010

Я не думаю, что это возможно без какой-либо формы поиска с переменной шириной. Добавление утверждения \K в 5.10 обеспечивает способ подделки положительного взгляда переменной ширины. Что нам действительно нужно, так это переменная ширина негатив оглядка назад, но с небольшим творческим потенциалом и большим уродством мы можем заставить его работать:

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;
4 голосов
/ 25 февраля 2010

Если вы должны опубликовать в переполнении стека, спрашивая, может ли кто-нибудь выяснить, как сделать это с негативным взглядом сзади, то это явно не хороший пример негативного взгляда сзади. Вам лучше придумать новый пример, чем пытаться его спасти.

В этом духе, как насчет автоматического корректора орфографии?

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

(Очевидно, это не сложное и быстрое правило на английском языке, но я думаю, что это более реалистичное применение негативного взгляда назад.)

0 голосов
/ 25 февраля 2010

Я не думаю, что это то, что вам нужно (особенно из-за того, что отрицательное косвенное утверждение было удалено), но я думаю, ваш единственный вариант - набрать десятичные знаки, как в этом примере:

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

P.S. Я думаю, что это хороший пример, когда его не используют в качестве первого в книге, поскольку он демонстрирует некоторые подводные камни и ограничения проверочных утверждений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...