Home > database >  How to verify that a part of a string matches a pattern using `pos`
How to verify that a part of a string matches a pattern using `pos`

Time:08-14

I might have obfuscated the real problem in my previous question, so here it is:

Let's suppose that you want to know if the characters from 7 to 15 are all 1 in a string:

my $str = "011000001111111111000011111110110111110000101010111";
my $i = 7, $j = 15;  # => start and end positions of the substring
my $l = $j - $i   1; # => length of the substrings 

I have thought of a few reasonable ways for doing the check

# 1. with `substr` and a regex:
printf "#1: %d\n", substr($str,$i,$l) =~ /\A1*\Z/;

# 2. with a regex from the beginning of the string:
printf "#2: %d\n", $str =~ /\A.{$i}1{$l}/;

# 3. with a regex and `pos`:
pos($str) = $i;
printf "#3: %d\n", $str =~ /1{$l}/;

I expect all results to be 0 (false) but I get:

#1: 0
#2: 0
#3: 1

What would be the correct regex when using pos in #3?

CodePudding user response:

You can do this with a simple regex.

/\A\d{6}1{9}/

Expanded to explain...

m{
  \A     # the beginning of the string
  \d{6}  # any six digits (digits 1 to 6)
  1{9}   # 9 1's (digits 7 to 15)
         # and we don't care about the rest
}x

The usual way to do this is with a bitmask.

# Convert the string to binary.
my $str = "011000001111111111000011111110110111110000101010111";
my $num = oct("0b$str");

# This is your bitmask.
my $mask = 0b000000001111111111000000000000000000000000000000000;

# AND each bit together. If the result equals the mask, it matches.
print "Match" if ($num & $mask) == $mask;

The advantage is this is probably faster and easier to understand (if you know what a bitmask is).

The disadvantage is this will only work up to 64 digits, assuming your Perl is compiled for 64 bit, which it should be in 2022, and only for 1s and 0s.

CodePudding user response:

Can walk through the string with regex

while (/(.)/g) { say "At pos ", pos, " is: $1" }

Or get chars at all positions and check with an array of the ones you care about

my @positions = 7 .. 15;

my @chars = split '';

for my $pos (@positions) { say "At $pos have: @chars[$pos-1]" }

But I'd rather prepare and use a bitmask as in Schwern's answer, if it's 1/0.

  •  Tags:  
  • perl
  • Related