Можете ли вы спасти мой отрицательный пример lookbehind для присвоения чисел?

В главе "Расширенное регулярное выражение" в Освоение 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

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

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

Ответ 1

Я не думаю, что это возможно без какой-либо формы с переменной шириной. Добавление утверждения \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;

Ответ 2

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

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

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

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

Ответ 3

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

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

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