use v5.12;
# demo for:
# http://stackoverflow.com/questions/17039670/vertical-regex-matching-in-an-ascii-image
^
(?:
(?: # match .+? characters
.
(?= # counting the same number on the following two lines
.*+\n
( \1?+ . )
.*+\n
( \2?+ . )
)
)+?
(?<= X ) # till the above consumes an X
(?= # that matches the following conditions
.*+\n
\1?+
(?<= X )
.*+\n
\2?+
(?<= X )
)
(?= # count the number of matches
.*+\n
( \3?+ . ) # the number of matches = length of $3
)
)* # repeat as long as there are matches on this line
.*\n? # remove the rest of the line
/xm;
my @tests = split /(?:\r?\n){2,}/, <<TESTS; X
X
X
..X....
..X....
..X....
..X.X..
..X.X..
....X..
..X....
..X....
...X...
..X....
...X...
..X....
....X..
.X..X..
.X.....
.X..X..
.X.X...
.X.X...
.X..X..
.X..X..
.X..X..
XXX
XXX
XXX
X.X.X
XXXXX
XXXXX
.X.X.
1....X.......
2..X..X...X....
3X.X...X..X.....
4X....XXXXXX.....
5X..XXX...........
6.....X..........
7.........X....X
8..X......X....X....
9..X......X....X....X...
A....X.....
B.X..X..
C.....
XXX
XXX
XXX
.
TESTS
for(my $i = 0; $i < @tests; ++$i){
my $test = $tests[$i];
say "Test #$i:";
say "-" x 20;
say "$test\n";
$test =~ s/$r/$3/g;
say
"result: ", length($test), " ($test)"; say "\n";
}
dXNlIHY1LjEyOwoKIyBkZW1vIGZvcjoKIyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzE3MDM5NjcwL3ZlcnRpY2FsLXJlZ2V4LW1hdGNoaW5nLWluLWFuLWFzY2lpLWltYWdlCgoKbXkgJHIgPSBxci8KXgooPzoKICAgICg/OiAgICAgICAgICAgICAgICAgICAjIG1hdGNoIC4rPyBjaGFyYWN0ZXJzCiAgICAgICAgLgogICAgICAgICg/PSAgICAgICAgICAgICAgICMgY291bnRpbmcgdGhlIHNhbWUgbnVtYmVyIG9uIHRoZSBmb2xsb3dpbmcgdHdvIGxpbmVzCiAgICAgICAgICAgIC4qK1xuCiAgICAgICAgICAgICggXDE/KyAuICkKICAgICAgICAgICAgLiorXG4KICAgICAgICAgICAgKCBcMj8rIC4gKQogICAgICAgICkKICAgICkrPwogICAgKD88PSBYICkgICAgICAgICAgICAgICMgdGlsbCB0aGUgYWJvdmUgY29uc3VtZXMgYW4gWAogICAgKD89ICAgICAgICAgICAgICAgICAgICMgdGhhdCBtYXRjaGVzIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucwogICAgICAgIC4qK1xuCiAgICAgICAgXDE/KwogICAgICAgICg/PD0gWCApCiAgICAgICAgLiorXG4KICAgICAgICBcMj8rCiAgICAgICAgKD88PSBYICkKICAgICkKICAgICg/PSAgICAgICAgICAgICAgICAgICAjIGNvdW50IHRoZSBudW1iZXIgb2YgbWF0Y2hlcwogICAgICAgIC4qK1xuCiAgICAgICAgKCBcMz8rIC4gKSAgICAgICAgIyB0aGUgbnVtYmVyIG9mIG1hdGNoZXMgPSBsZW5ndGggb2YgJDMKICAgICkKKSogICAgICAgICAgICAgICAgICAgICAgICAjIHJlcGVhdCBhcyBsb25nIGFzIHRoZXJlIGFyZSBtYXRjaGVzIG9uIHRoaXMgbGluZQouKlxuPyAgICAgICAgICAgICAgICAgICAgICMgcmVtb3ZlIHRoZSByZXN0IG9mIHRoZSBsaW5lCi94bTsKCgpteSBAdGVzdHMgPSBzcGxpdCAvKD86XHI/XG4pezIsfS8sIDw8VEVTVFM7ClgKWApYCgouLlguLi4uCi4uWC4uLi4KLi5YLi4uLgoKLi5YLlguLgouLlguWC4uCi4uLi5YLi4KCi4uWC4uLi4KLi5YLi4uLgouLi5YLi4uCgouLlguLi4uCi4uLlguLi4KLi5YLi4uLgoKLi4uLlguLgouWC4uWC4uCi5YLi4uLi4KCi5YLi5YLi4KLlguWC4uLgouWC5YLi4uCgouWC4uWC4uCi5YLi5YLi4KLlguLlguLgoKWFhYClhYWApYWFgKClguWC5YClhYWFhYClhYWFhYCi5YLlguCgoKMS4uLi5YLi4uLi4uLgoyLi5YLi5YLi4uWC4uLi4KM1guWC4uLlguLlguLi4uLgo0WC4uLi5YWFhYWFguLi4uLgo1WC4uWFhYLi4uLi4uLi4uLi4KNi4uLi4uWC4uLi4uLi4uLi4KNy4uLi4uLi4uLlguLi4uWAo4Li5YLi4uLi4uWC4uLi5YLi4uLgo5Li5YLi4uLi4uWC4uLi5YLi4uLlguLi4KQS4uLi5YLi4uLi4KQi5YLi5YLi4KQy4uLi4uClhYWApYWFgKWFhYCi4KClRFU1RTCgoKZm9yKG15ICRpID0gMDsgJGkgPCBAdGVzdHM7ICsrJGkpewogICAgbXkgJHRlc3QgPSAkdGVzdHNbJGldOwoJc2F5ICJUZXN0ICMkaToiOwoJc2F5ICItIiB4IDIwOwoJc2F5ICIkdGVzdFxuIjsKCQoJJHRlc3QgPX4gcy8kci8kMy9nOwoJCglzYXkgInJlc3VsdDogIiwgbGVuZ3RoKCR0ZXN0KSwgIiAoJHRlc3QpIjsKCXNheSAiXG4iOwp9Cg==