Advertisement
snake5

regex alternative basic impl v0.1

Feb 27th, 2013
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 4.74 KB | None | 0 0
  1. <?php
  2.  
  3. $test = "crud <img src='blah' alt='foo' /> crud";
  4.  
  5. //$expr = "string '<img' not string '/>' string 'src=' extract quoted '\\'','\\\"' '\\\\' not string '<img' string '/>'";
  6. $expr = "string '<img' not string '/>' string 'src=' not string '<img' string '/>'";
  7.  
  8.  
  9. function hdr( $name ){ echo "<h3>{$name}</h3>\n"; }
  10.  
  11. /*
  12.     Tokenize
  13. */
  14. function coltok( $toks )
  15. {
  16.     $out = array();
  17.     foreach( $toks as $tok )
  18.         $out []= "{ type={$tok->type}, data='{$tok->data}', pos={$tok->pos} }";
  19.     return $out;
  20. }
  21. function mktoken( $type, $data, $pos ){ return (object) array( 'type' => $type, 'data' => $data, 'pos' => $pos ); }
  22. function te_parse_number( $expr, &$i, $len, &$out, &$errors )
  23. {
  24.     $pos = $i;
  25.     while( strpos( "0123456789", $expr[ $i ] ) !== false )
  26.         $i++;
  27.     $out[] = mktoken( 'ident', substr( $expr, $pos, $i - $pos ), $pos );
  28. }
  29. function te_parse_ident( $expr, &$i, $len, &$out, &$errors )
  30. {
  31.     $pos = $i;
  32.     while( strpos( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_", $expr[ $i ] ) !== false )
  33.         $i++;
  34.     $out[] = mktoken( 'ident', substr( $expr, $pos, $i - $pos ), $pos );
  35. }
  36. function te_parse_string( $expr, &$i, $len, &$out, &$errors )
  37. {
  38.     $pos = $i;
  39.     $ec = $expr[ $i ];
  40.     $i++;
  41.     $outstr = '';
  42.     for( ; $i < $len; ++$i )
  43.     {
  44.         $c = $expr[ $i ];
  45.         if( $c == '\\' )
  46.         {
  47.             $i++;
  48.             $nc = $expr[ $i ];
  49.             if( $nc == 'n' ) $outstr .= "\n";
  50.             elseif( $nc == 't' ) $outstr .= "\t";
  51.             elseif( $nc == '\\' ) $outstr .= '\\';
  52.             else
  53.                 $outstr .= $c.$nc;
  54.         }
  55.         elseif( $c == $ec )
  56.         {
  57.             $out[] = mktoken( 'string', $outstr, $pos );
  58.             return;
  59.         }
  60.         else
  61.             $outstr .= $c;
  62.     }
  63. }
  64. function tokenize_expr( $expr )
  65. {
  66.     $len = strlen( $expr );
  67.     $out = array();
  68.     $errors = array();
  69.     for( $i = 0; $i < $len; ++$i )
  70.     {
  71.         $c = $expr[ $i ];
  72.        
  73.         // whitespace
  74.         if( strpos( " \t\n\r", $c ) !== false )
  75.             continue;
  76.         // special symbols
  77.         elseif( strpos( ",", $c ) !== false )
  78.             $out[] = mktoken( 'special', $c, $i );
  79.         // strings
  80.         elseif( strpos( "\'\"", $c ) !== false )
  81.             te_parse_string( $expr, $i, $len, $out, $errors );
  82.         // numbers
  83.         elseif( strpos( "0123456789", $c ) !== false )
  84.             te_parse_number( $expr, $i, $len, $out, $errors );
  85.         // keywords
  86.         elseif( strpos( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_", $c ) !== false )
  87.             te_parse_ident( $expr, $i, $len, $out, $errors );
  88.         else
  89.             $errors[] = "invalid character at position {$i} ({$c})";
  90.     }
  91.     if( count( $errors ) )
  92.     {
  93.         var_dump( coltok( $out ), $errors );
  94.         die;
  95.     }
  96.     return $out;
  97. }
  98.  
  99. hdr( 'tokenizer' );
  100. $tokens = tokenize_expr( $expr );
  101. var_dump( coltok( $tokens ) );
  102.  
  103.  
  104. function mkparseitem( $type, $data ){ return (object) array( 'type' => $type, 'data' => $data ); }
  105. function gen_parsetree( $tokens, &$from = null )
  106. {
  107.     $ptree = array();
  108.     $len = count( $tokens );
  109.     $errors = array();
  110.     $i = 0;
  111.     $onlyone = false;
  112.     if( isset( $from ) )
  113.     {
  114.         $i = $from;
  115.         $onlyone = true;
  116.     }
  117.     for( ; $i < $len; ++$i )
  118.     {
  119.         $token = $tokens[ $i ];
  120.        
  121.         if( $token->type == 'ident' && $token->data == 'string' )
  122.         {
  123.             $i++;
  124.             if( $tokens[ $i ]->type != 'string' )
  125.             {
  126.                 $errors[] = "expected string after 'string'";
  127.                 $i--; continue;
  128.             }
  129.             $ptree[] = mkparseitem( 'string', $tokens[ $i ]->data );
  130.         }
  131.         elseif( $token->type == 'ident' && $token->data == 'not' )
  132.         {
  133.             $i++;
  134.             $notwhat = gen_parsetree( $tokens, $i );
  135.             $i++;
  136.             $befwhat = gen_parsetree( $tokens, $i );
  137.             $ptree[] = mkparseitem( 'not', array( $notwhat, $befwhat ) );
  138.         }
  139.         else
  140.         {
  141.             $errors[] = "unexpected token found: {$token->type} '{$token->data}'";
  142.         }
  143.         if( $onlyone )
  144.         {
  145.             $from = $i;
  146.             break;
  147.         }
  148.     }
  149.     if( count( $errors ) )
  150.     {
  151.         var_dump( $ptree, $errors );
  152.         die;
  153.     }
  154.     return $ptree;
  155. }
  156.  
  157. hdr( 'parsing tree' );
  158. $ptree = gen_parsetree( $tokens );
  159. var_dump( $ptree );
  160.  
  161.  
  162. function do_matching( $ptree, $str, $ofs = 0 )
  163. {
  164.     $first = null;
  165.     foreach( $ptree as $pitem )
  166.     {
  167.         if( $pitem->type == 'string' )
  168.         {
  169.             $pos = strpos( $str, $pitem->data, $ofs );
  170.             if( $pos === false )
  171.                 return false;
  172.             else
  173.             {
  174.                 if( $first === null )
  175.                     $first = $pos;
  176.                 $ofs = $pos + strlen( $pitem->data );
  177.             }
  178.         }
  179.         else if( $pitem->type == 'not' )
  180.         {
  181.             $p1 = do_matching( $pitem->data[0], $str, $ofs );
  182.             $p2 = do_matching( $pitem->data[1], $str, $ofs );
  183.             if( $p2 === false || ( $p1 !== false && $p1[0] < $p2[0] ) )
  184.                 return false;
  185.             if( $first === null )
  186.                 $first = $p2[ 0 ];
  187.             $ofs = $p2[1];
  188.         }
  189.     }
  190.     return array( $first, $ofs );
  191. }
  192.  
  193. hdr( 'matching' );
  194. $out = do_matching( $ptree, $test );
  195. var_dump( $out );
  196. if( $out === false )
  197.     echo "no matches\n";
  198. else
  199. {
  200.     $match = substr( $test, $out[0], $out[1]-$out[0] );
  201.     echo "match: '{$match}'\n";
  202. }
  203.  
  204.  
  205.  
  206. /* final output:
  207. match: '<img src='blah' alt='foo' />'
  208. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement