Can you salvage my negative lookbehind example for commifying numbers?

后端 未结 3 725
旧时难觅i
旧时难觅i 2021-02-04 04:44

In the \"Advanced Regular Expresssion\" chapter in Mastering Perl, I have a broken example for which I can\'t figure out a nice fix. The example is perhaps trying to be too clev

相关标签:
3条回答
  • 2021-02-04 05:05

    I don't think it's possible without some form of variable-width look-behind. The addition of the \K assertion in 5.10 provides a way of faking variable-width positive look-behind. What we really need is variable-width negative look-behind but with a little creativity and a lot of ugliness we can make it work:

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

    If there was ever a pattern that begged for the /x notation it's this one:

    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;
    
    0 讨论(0)
  • 2021-02-04 05:11

    If you have to post on Stack Overflow asking if somebody can figure out how to do this with negative lookbehind, then it's obviously not a good example of negative lookbehind. You'd be better off thinking up a new example rather than trying to salvage this one.

    In that spirit, how about an automatic spelling corrector?

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

    (Obviously, that's not a hard and fast rule in English, but I think it's a more realistic application of negative lookbehind.)

    0 讨论(0)
  • 2021-02-04 05:12

    I don't think this is what you are after (especially becaue the negative look-behind assertion has been dropped), but I guess, your only option is to slurp up the decimal places like in this example:

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

    P.S. I think it is a good example when not used as the first one in the book, as it demonstrates some of the pitfalls and limitations of look-around assertions.

    0 讨论(0)
提交回复
热议问题