Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add "m" modifier to qr pattern passed as parameter

Tags:

regex

perl

I would like to be able to add the "m" modifier to a regex that was passed to a function.

The following test script demonstrates what I'm trying to do

#!/usr/bin/env perl

use strict;
use warnings;
use v5.16.3;

use Test::More tests => 3;

my $no_m_modifier_re   = qr{^line1\n^line2};
my $with_m_modifier_re = qr{^line1\n^line2}m;

my $text = <<'EoM';
line1
line2
line3
EoM

unlike( $text, $no_m_modifier_re, 'Text will not match ^ that is equivalent to \A' );
like( $text, $with_m_modifier_re, 'Text will match ^ with m modifier' );

# This fails to add the m modifier to the subexpression
my $add_m_modifier_re = qr{(?m)$no_m_modifier_re};
#my $add_m_modifier_re = qr{(?m:$no_m_modifier_re)};    # Experimented other syntax, with same result
#my $add_m_modifier_re = qr{$no_m_modifier_re}m;
#my $add_m_modifier_re = qr{(?^m:$no_m_modifier_re)};    # suggested by mob, didn't work.

like( $text, $add_m_modifier_re, 'Want this to match, but it fails to add m modifier to subexpression' );

The results are

$ prove -v m_modifier.pl
m_modifier.pl ..
1..3
ok 1 - Text will not match ^ that is equivalent to \A
ok 2 - Text will match ^ with m modifier
not ok 3 - Want this to match, but it fails to add m modifier to subexpression

#   Failed test 'Want this to match, but it fails to add m modifier to subexpression'
#   at m_modifier.pl line 25.
#                   'line1
# line2
# line3
# '
#     doesn't match '(?^:(?m)(?^:^line1\n^line2))'
# Looks like you failed 1 test of 3.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/3 subtests

Test Summary Report
-------------------
m_modifier.t (Wstat: 256 Tests: 3 Failed: 1)
  Failed test:  3
  Non-zero exit status: 1
Files=1, Tests=3,  1 wallclock secs ( 0.04 usr  0.01 sys +  0.14 cusr  0.05 csys =  0.24 CPU)
Result: FAIL

As you can see, I experimented with different syntax for adding the m modifier, but none of them appear to apply to the original pattern.

Any ideas?

This is under Perl 5.16.3. I have not tried more modern versions.

like image 833
Miller Avatar asked Dec 17 '20 19:12

Miller


People also ask

Is it possible to customize QR codes?

Yes, it is possible to customize QR codes IF you created them in InDesign. Just select the QR code and the same menu item (Objects - Generate QR Code) you used for creating becomes "Edit QR Code" (or just Right-Click the QR Code -> Edit QR Code) Placing a logo on top you have to do manually nevertheless. Off topic: paying for QR codes?!

How to check if the m modifier is set?

The "m" modifier is case-sensitive and not global. To perform a global, case-insensitive search, use "m" with "g" and "i". A global, case-insensitive, multiline search for "is" at the beginning of each string line: let text = "Is this his ?"; Use the multiline property to check if the m modifier is set.

What is the m modifier used for in SQL?

The m modifier is used to perform a multiline match. The m modifier treat beginning (^) and end ($) characters to match the beginning or end of each line of a string (delimited by n or r), rather than just the beginning or end of the string. Note: The m modifier is case-sensitive and will stop the search after the first match.

What is the use of M modifier in Python?

Definition and Usage The m modifier is used to perform a multiline match. The m modifier treat beginning (^) and end ($) characters to match the beginning or end of each line of a string (delimited by n or r), rather than just the beginning or end of the string.


2 Answers

The problem is that you need to change a qr-ed expression, which is a regex object which

...magically differs from a string containing the same characters: ref(qr/x/) returns "Regexp"; however, dereferencing it is not well defined...

I can't find a way to change it, or add a flag to it (other than to edit its stringification).

However, if you can change the approach so to define (non-qr) variables to start with and then later qr-them as needed then it works as desired

use strict;
use warnings;
use v5.16.3;

use Test::More tests => 3;

my $no_m_modifier_re   = q{^line1\n^line2};  # not qr{} but q{}; just a string

my $text = <<'EoM';
line1
line2
line3
EoM

unlike( $text, qr{$no_m_modifier_re}, 'Text does not match ^ equivalent to \A' );

like(   $text, qr{$no_m_modifier_re}m, 'Text matches with the modifier' );

like(   $text, qr{(?m)$no_m_modifier_re}, 'Text matches with the modifier' );

Along with strings one can set up qr-ed variables as well, for convenience, but the main idea is that the user forms a regex pattern along with needed fine-tuning, for example by modifiers.


If either may get passed around they can be told apart by ref

like image 106
zdim Avatar answered Oct 16 '22 13:10

zdim


I tried qr{(?^m:$no_m_modifier_re)} like you suggested, but it still fails. The test reports doesn't match '(?^u:(?^m:(?^u:^line1\n^line2)))'

You are trying to modify a compiled pattern. For that, you need the following:

use re qw( is_regexp regexp_pattern );

my $re = qr/^line1\n^line2/;

my ($pat, $mods) =
   is_regexp($re)
      ? regexp_pattern($re)
      : ( $re, "" );

$mods .= 'm' if $mods !~ /m/;

$re = eval("qr/\$pat/$mods")
   or die($@);  # Should never happen.

It also works with uncompiled patterns, resulting in a compiled pattern with minimal (?:) nesting.

The result for   "abc"       is   qr/abc/m    which stringifies as   (?^um:abc)
The result for   qr/abc/     is   qr/abc/m    which stringifies as   (?^um:abc)
The result for   qr/abc/m    is   qr/abc/m    which stringifies as   (?^um:abc)
The result for   qr/abc/s    is   qr/abc/sm   which stringifies as   (?^ums:abc)
The result for   qr/abc/sm   is   qr/abc/sm   which stringifies as   (?^ums:abc)
like image 31
ikegami Avatar answered Oct 16 '22 13:10

ikegami