18

MasteringPerlの「AdvancedRegularExpresssion」の章に、良い修正がわからない壊れた例があります。この例は、おそらくそれ自体の利益のために賢くなりすぎようとしているのかもしれませんが、誰かが私のためにそれを修正できるかもしれません。修正作業のために、本の無料コピーが含まれている可能性があります。:)

ルックアラウンドについて説明しているセクションでは、ネガティブルックビハインドを使用して、小数部の数値のコミュニケートルーチンを実装したいと思いました。ポイントは、それがトピックだったので、ネガティブルックビハインドを使用することでした。

私は愚かにこれをしました:

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

は、の(?<!\.\d)前のビット(?=(?:\d\d\d)+\b)が小数点および数字ではないことを表明します。

愚かなことはそれを壊すのに十分な努力をしていません。最後に別の数字を追加することにより、小数点と数字が前に付いていない3桁のグループができます。

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

Perlで後読みが可変幅である可能性がある場合、これは非常に簡単でした。しかし、彼らはできません。

ネガティブな裏返しなしでこれを行うのは簡単ですが、それは例のポイントではないことに注意してください。この例を救う方法はありますか?

4

3 に答える 3

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;
于 2010-02-25T21:03:45.893 に答える
4

スタック オーバーフローに投稿して、誰か負の後読みでこれを行う方法を見つけられるかどうか尋ねなければならない場合、それは明らかに負の後読みの良い例ではありません。この例を救おうとするよりも、新しい例を考えたほうがよいでしょう。

その精神で、自動スペル修正機能はどうですか?

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

(明らかに、これは英語では厳密で迅速なルールではありませんが、否定的な後読みのより現実的なアプリケーションだと思います。)

于 2010-02-25T00:10:10.020 に答える
0

これはあなたが求めているものではないと思います (特に否定的な後読みアサーションが削除されたため) が、唯一のオプションは、この例のように小数点以下の桁数を丸呑みにすることだと思います:

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

PS これは、本書の最初の例として使用されていない場合の良い例だと思います。これは、ルックアラウンド アサーションのいくつかの落とし穴と制限を示しているためです。

于 2010-02-25T08:42:19.300 に答える