6

I've a string describing a matrix of n x m elements like this one:

§inputmap = "
~~~~~~~~~~~~~~~~~~~~B~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~BBB........BBB~~~~~~~~~~~~~
~~~~~~~~~~BB...............FBB~~~~~~~~~~
~~~~~~~~BB....................BB~~~~~~~~
~~~~~~BB.....F..................BB~~~~~~
~~~~~BB.....................F.....B~~~~~
~~~~B..............................B~~~~
~~~B........F.......................B~~~
~~BB.........F......................BB~~
~~B................F.................BB~
~BF....F....F........................FB~
~B.....................................B
B.....................................FB
B........F......F......................B
B...........................F..........B
B......................................B
B......................................B
B.......F.......................F......B
B......FFF.............................B
B.......F.............................FB
~B..................F.................FB
~BF...........................F.......B~
~~B...F...........F..........FFFFF.F.BB~
~~BB..................F..F....F.....BB~~
~~~B.......................FF.FF....B~~~
~~~~B..............................B~~~~
~~~~~BB...........................B~~~~~
~~~~~~BB........................BB~~~~~~
~~~~~~~~BB..........F..........B~~~~~~~~
~~~~~~~~~~BB................BB~~~~~~~~~~
~~~~~~~~~~~~~BBB.......F.BBB~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~BBBBBB~~~~~~~~~~~~~~~~~
";
$inputmap = trim($inputmap);

I need to build a regular expression (or something else) to search the string:

$search = "
*F*
FFF
*F*
";
$search = trim($search);

on the whole grid. On other hands I need to find a pattern of 5 distinct letter "F" (3 vertically and 3 horizzontally) getting back the rows/columns position of the pattern(s) found on the map.

Considering that the input matrix can be different (5x5 or 10x10 or 20x25 or ...), is there a way to solve my problem with php and regular expressions?

CSᵠ
  • 9,711
  • 9
  • 37
  • 61
Stefano Radaelli
  • 966
  • 1
  • 13
  • 28
  • 2
    I don't think that regular expressions are the right tool for this job. You should convert the string into a two dimensional array and search through the array. This could be done in "linear" time (actually, if it's a square matrix of side length n, it can be easily done in (n)^2 time) – FrankieTheKneeMan Jun 10 '13 at 14:43
  • Your problem is too complex to use a regular expression. Write a little script that seeks the first line of your search in the input and verify if other lines match below playing with array indexes – ffarquet Jun 10 '13 at 14:43
  • 1
    First, can you show us what you have tried; we are here to help not do everything for you. The general solution is for each set check a sub-section of the grid cols(0-2) and rows(0-2) then move over one; and keep checking until you hit the end of the row. Then move one column down at cols(0-2) and rows(1-3) and keep reading to the right until you reach the bottom right of your array. You can either solve this through array indexing or creating a huge string and parsing it that way. – Devon Bernard Jun 10 '13 at 14:44
  • FrankieTheKneeMan, thank you for your suggestion... I would try to implement something following your suggestion. ffarquet, is this the unque approach possibile? At least as far as you see? Devon, you're absolutely right! I'm not asking to anyone to provide me a solution by scratch but to compare instead my approach with a better one provided by someone that had my same problem. By the way I fully agree with you! – Stefano Radaelli Jun 10 '13 at 14:52
  • out of curiosity, would `"FFF\nFFF\nFFF"` match? – FrankieTheKneeMan Jun 10 '13 at 15:24

5 Answers5

4

You can use $length=strstr($inputmap,"\n") to find the width of each line. You can then construct a regular expression that will find an F, followed by ($length-2) other characters, followed by 3 Fs, followed by ($length-2) other characters, followed by an F.

IanPudney
  • 5,531
  • 1
  • 20
  • 37
3

You can do something like this (without regular expressions) :

$map = explode("\n", $inputmap);

for ($vcount = 0; $vcount < sizeof($map); ++$vcount) {  // Loop through the map vertically
    for ($hcount = 0; $hcount < strlen($map[$vcount]); ++$hcount) { // Loop through each character of each line
        if ($map[$vcount][$hcount] == "F") {
            if ($map[$vcount + 1][$hcount - 1] == "F" && $map[$vcount + 1][$hcount] == "F" && 
                $map[$vcount + 1][$hcount + 1] == "F" && $map[$vcount + 2][$hcount] == "F")
                echo "Pattern found, starting at : (v)$vcount x (h)$hcount";
        }
    }
}

$> php test.php
php test.php
Pattern found, starting at : (v)18 x (h)8
Pattern found, starting at : (v)22 x (h)30
$>

But I must admit that it could take a while for extra-big maps.

/!\ add some code to verify that the line $vcount + 1/2 actually exists, and the char $hcount + 1 too.

B F
  • 7,287
  • 12
  • 44
  • 78
2

You could use the following code:

$lines = array_filter(preg_split("#\r\n?|\n#", $string)); // Creating array of lines
$matrix = array_map('str_split', $lines); // Creating a matrix

foreach($lines as $line_number => $line_content){ // Looping through the lines
    $pos = strpos($line_content, 'FFF');
    if(!$pos === false){// If FFF found
        while(true){
            if(isset($matrix[$line_number-1][$pos+1],$matrix[$line_number+1][$pos+1]) && $matrix[$line_number-1][$pos+1] == 'F' && $matrix[$line_number+1][$pos+1] == 'F'){ //Checking ...
                echo 'Found at: X:'.$pos.' & Y:'.$line_number.'<br>'; // Ouput
            }
            $pos = strpos($line_content, 'FFF', $pos+1); // Search further
            if(!is_int($pos)){
                break;
            }
        }
    }
}

What's going on ?

  1. We create an array of lines
  2. We create a matrix
  3. We loop through the lines and search for FFF this is to increase performance. So instead of looping through the whole matrix and searching for F, we directly search for FFF
  4. Check if the value exists in the matrix (to prevent undefined index errors) and then check if it equals F
  5. Output
  6. Search further on the same line

Online demo

Note that the coordinates are the center of the +

HamZa
  • 13,530
  • 11
  • 51
  • 70
1

try with this pattern:

if the end of line is \n:

$pattern = '~F.{'. ($n-2) . '}FFF.{' . ($n-2) . 'F~s';

if the end of line is \r\n then replace by $n-3

or better use quinxorin trick to know the line length until the \n

Casimir et Hippolyte
  • 83,228
  • 5
  • 85
  • 113
1

@FrankieTheKneeMan & all... my initial approach was to build 'n' regular expression for 'n' chars of the input grid map. Something like...

$search_001 = "
.F......................................
FFF.....................................
.F......................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
";


$search_002 = "
..F.....................................
.FFF....................................
..F.....................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
";

(... omissis ...)

$search_100 = "
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
..........F.............................
.........FFF............................
..........F.............................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
";

(... omissis ...)

$search_999 = "
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
......................................F.
.....................................FFF
......................................F.
";

where "." obvioulsy means any character.

Is this a stupid idea?!?

Stefano Radaelli
  • 966
  • 1
  • 13
  • 28