in reply to Re: This regexp made simpler
in thread This regexp made simpler

But that doesn't match 'AZ', which the OP seems to require, and also doesn't match 'A Z' (single space between first and final characters), which also seems to be required.

Replies are listed 'Best First'.
Re^3: This regexp made simpler
by moritz (Cardinal) on Apr 25, 2010 at 12:23 UTC
    A simple variation fixes that:
    /A( [^Z]*)?Z/

    It surprises me how many monks in this thread seem to think that expressing the "no Z between ..." condition with .*? is a good idea.

      Indeed. That was the main point I was going to contribute, but you've beat me to it.

      The OP even specifically says he wants to match "any number of characters not containing Z", which is properly written [^Z]*. .*?Z means "the shortest available sequence of any character at all (except, usually, newlines), followed by a Z", which is not quite the same thing.

      But doesn't that still give you an undefined  $1 that needs to be 'fixed' sooner or later?

      >perl -wMstrict -le "'AZ' =~ /A( [^Z]*)?Z/; print qq{'$1'}; " Use of uninitialized value $1 in concatenation (.) or string at ... ''

      'Elegance', admittedly protean, would yet seem to require avoiding this extra step.

      It surprises me how many monks in this thread seem to think that expressing the "no Z between ..." condition with .*? is a good idea.
      Maybe because it saves you from writing Z twice, which can be a maintenance issue? This is true especially if Z happens not to be just a latter, but a more complicated pattern.

      -- 
      Ronald Fischer <ynnor@mm.st>
        Huh.

        I prefer a correct solution that contains some repetition to an incorrect solution any time. There are ways to make .*? work correctly, but they include a certain amount of backtracking control, which makes them harder to maintain.

        This is true especially if Z happens not to be just a latter, but a more complicated pattern.

        If that's the case, you should use interpolation anyway, and [^Z]+ is to be replaced by (?s:(?!$Z).)+

        In general it does make a difference if Z is actually a single character or something else, and if it's something else that should be mentioned in the original question anyway.

        Update: added missing quantifier

        Perl 6 - links to (nearly) everything that is Perl 6.
        This is true especially if Z happens not to be just a latter, [sic] but a more complicated pattern.

        To expand on moritz's Re^5: This regexp made simpler: This, I think, is exactly the motivation behind regex objects. Using really non greedy match as an example, some regex objects can be factored out and treated as if they were atomic – because they are, more or less! (The big gotcha is that things get tricky if the factored regexes contain capturing groups, which consequently should be avoided. This problem is ameliorated by 5.10's relativistic approach to referencing capture variables.) The 'regex factoring' approach can lead to a lot more initial verbosity, but this cost is repaid many-fold by greater ease in conceptualizing, building and maintaining complex regexes.

        In the example below,  $not_S* and  $not_S*? work as one would expect for  .* and  .*? expressions. (There is a problem with the counting quantifiers {n} et al: something like  $not_S{3} looks like a hash element; the more awkward  (?:$not_S){3} must be used instead.)[See update] Note that something like  $S or  $E could be a much more complicated (and factored) pattern.

        >perl -wMstrict -le "$_ = 'no a START no b START yes c END maybe d END no e START yes f END'; my $S = qr{ START }xms; my $E = qr{ END }xms; my $not_S = qr{ (?! $S) . }xms; my $Lazy = qr{ $S $not_S*? $E }xms; print qq{'$_'}; print 'greedy: ', map qq{'$_' }, m{ $S $not_S* $E }xmsg; print 'lazy: ', map qq{'$_' }, m{ $S $not_S*? $E }xmsg; print 'compound: ', map qq{'$_' }, m{ $Lazy }xmsg; " 'no a START no b START yes c END maybe d END no e START yes f END' greedy: 'START yes c END maybe d END' 'START yes f END' lazy: 'START yes c END' 'START yes f END' compound: 'START yes c END' 'START yes f END'

        Update: Somehow I had the idea that  $scalar{3} in a regex would interpolate like a hash element, but I just tested this in 5.10 and AS 5.8.9 and 'taint so. Where did I get this notion? Update: Ah,  $scalar{'7'} and  $scalar{$n} interpolate like hash elements and  (?:$scalar){$n} looks like a quantifier again; problem solved.

Re^3: This regexp made simpler
by BrowserUk (Patriarch) on Apr 25, 2010 at 12:23 UTC

    Ah yes, missed that. Maybe this improved version.

    printf( "\n$_: " ), m[A( [^Z]*|)Z] and print "'$1'" for 'AZ', 'A SOMETHING Z', 'ASOMETHINGZ', 'A Z', 'A Z';; AZ: '' A SOMETHING Z: ' SOMETHING ' ASOMETHINGZ: A Z: ' ' A Z: ' '

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.