Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Multiline match for empty string

by josh803316 (Beadle)
on Aug 05, 2010 at 16:51 UTC ( #853178=perlquestion: print w/replies, xml ) Need Help??
josh803316 has asked for the wisdom of the Perl Monks concerning the following question:

I have a multi-line match regex qr{$regex}ms that I want to fail when my string is non-empty. I have noticed that for the following text value(example) it matches and passes because the 2nd line is empty with just a newline. How can I maintain this multiline match regex format but always fail for any text that is returned even if one line contains no text:
#!/usr/bin/perl use strict; use warnings; my $tests = '% only 1 profile is allowed '; my $regex = '^$'; if($tests =~ qr{$regex}ms) { print "$tests\n REGEX MATCHED\n"; } else { print "$tests\n FAILED!\n"; }

Replies are listed 'Best First'.
Re: Multiline match for empty string
by kennethk (Abbot) on Aug 05, 2010 at 17:01 UTC
    Rather than positively matching against empty lines, why don't you match negatively for non-whitespace characters?

    #!/usr/bin/perl use strict; use warnings; my $tests = '% only 1 profile is allowed '; my $regex = '\S'; if($tests !~ qr{$regex}ms) { print "$tests\n REGEX MATCHED\n"; } else { print "$tests\n FAILED!\n"; }

    You could also dynamically build your regular expression based upon the string itself:

    my $regex = '^\n{' . $tests =~ tr/\n/\n/ . '}';

    If neither of these meet spec, I'd appreciate a more thorough description of what you mean by "maintain this multiline match regex format". I sense this is an XY Problem.

      What I mean is, in the flow of the application I can only pass a regex but the logic of the comparison won't change:
      $tests =~ qr{$regex}ms

      So I was wondering if there was a regex I could pass besides ^$ that would fail the match for anything that wasn't a single empty space ''.
        It's probably easier and cleaner to just write a one-off test rather than working within this fixed framework, but you could use this to check if your test string contains only whitespace:

        my $regex = q|(??{'\s{' . length($tests) . '}'})|;

        This requires you to include use re 'eval'; at some point in scope. It also requires that the name of of the variable being tested is literally $tests - if not, you need to modify the string accordingly.

        How it works:
        The expression uses Perl code executed at matching time - see (??{ code }) in perlre. The string literal stored in $regex is (??{'\s{' . length($tests) . '}'}). When the regular expression is executed, Perl concatenates '\s{', the length of the variable $tests and '}'. The resulting regular expression requires that the string in question match exactly as many whitespace characters as there are characters in the string, i.e. contain only whitespace. You should also note that this opens up some security holes in Perl, as discussed in (??{ code }) and in A bit of magic: executing Perl code in a regular expression from perlretut.

Re: Multiline match for empty string
by Anonymous Monk on Aug 05, 2010 at 16:57 UTC


    An empty string can't contain a newline

    Why not just do a quick scan for two newlines in a row before you go and do the main regex?

Re: Multiline match for empty string
by ikegami (Pope) on Aug 05, 2010 at 20:39 UTC

    "(?!.*[^\n])" or "(?!.*\\S)" depending on how strict you want to be.

      Either I misunderstand the spec, or your solution fails:

      #!/usr/bin/perl use strict; use warnings; my @tests = ("\% only 1 profile is allowed\n\n", # Should fail "\n\n", # Should pass "", # Should pass ); my $regex = "(?!.*\\S)"; for (@tests) { print $_ =~ qr{$regex}ms ? "$_\n REGEX MATCHED\n" : "$_\n FAILED!\ +n"; }

      Like with the bad OP proposal, your regex passes for all cases.

      Update: Fixed mistake in posted test, though it does not change the result. See below for corrected regular expression.

        I forgot to anchor. Should be

        "\\A(?!.*[^\n])" or "\\A(?!.*\\S)"

        Of course, the following are much simpler:

        "\\A[^\n]*\\z" or "\\A\\s*\\z"

        By the way, your test is wrong. You never actually attempt to match.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://853178]
Approved by kennethk
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2018-04-25 18:45 GMT
Find Nodes?
    Voting Booth?