2011-07-27 8 views
1

うまくいけば、これは簡単なことです。JSを圧縮ルーチンから除外するregex/preg_replace式のヘルプ

私はこのコードを私のcodeigniterアプリで使用して、ホワイトスペースなどを取り除いています。 (Jerome Jaglale経由) - link

function compress() 
{ 
    $CI =& get_instance(); 
    $buffer = $CI->output->get_output(); 

    $search = array(
     '/\>[^\S ]+/s', 
     '/[^\S ]+\</s', 
     '/(\s)+/s', // shorten multiple whitespace sequences 
     '#(?://)?<!\[CDATA\[(.*?)(?://)?\]\]>#s' //leave CDATA alone 
    ); 
    $replace = array(
     '>', 
     '<', 
     '\\1', 
     "//&lt;![CDATA[\n".'\1'."\n//]]>" 
    ); 

    $buffer = preg_replace($search, $replace, $buffer); 

    $CI->output->set_output($buffer); 
    $CI->output->_display(); 
} 

問題は、この圧縮ルーチンからインラインjQueryを除外する必要があることです。私のjQueryは常に<script></script>タグ内ですが、このコードでは<![CDATA[]]>(10行目と16行目)の使用を検討しています。

CDATAの代わりに<script>を除外しましたが、それは正しくできません。

誰もが光を見せてくれませんか?

私はCDATAタグも<script type="text/javascript">も使用していないことがわかります。これが絶対に必要と思われる場合は、これを反映する必要があるかもしれません。

答えて

0

私はここで解決策を見つけた:

http://www.enapupe.com.br/blog/65/codeigniter-minify-html-output/

をこれは非常にうまく機能し、私のjQueryを壊していません。

これは、W3 Total CacheとWp-minify(Wordpressプラグイン)で使用されるMinifyプロジェクトに適合したCIライブラリです。

0
私は縮小化、出力するHTMLのために、このトリックを使用

、CSS CodeIgniterの中& JS:

function compress() { 
    $CI =& get_instance(); 
    $CI->output->set_output(Minifyhtml::minify($CI->output->get_output(), array('is_xhtml'=>null, 'js_clean_comments'=>false, 'cssMinifier'=>'Minify_CSS::minify', 'jsMinifier'=>'Minify_JS::minify'))); 
    $CI->output->_display(); 
} 

class Minifyhtml { 
    protected $is_xhtml    = null; 
    protected $js_clean_comments = true; 
    protected $replacement_hash  = null; 
    protected $placeholders   = array(); 
    protected $css_minifier   = null; 
    protected $js_minifier   = null; 
    public static function minify($html, $options = array()) { 
     $min = new self($html, $options); 
     return $min->process(); 
    } 
    public function __construct($html, $options = array()) { 
     $this->html = str_replace("\r\n", "\n", trim($html)); 
     $this->html = str_replace("\r\r", "\n", $this->html); 
     $this->html = str_replace("\n\n", "\n", $this->html); 
     if(isset($options['is_xhtml'])) { $this->is_xhtml = (bool)$options['is_xhtml']; } 
     if(isset($options['js_clean_comments'])) { $this->js_clean_comments = (bool)$options['js_clean_comments']; } 
     if(isset($options['cssMinifier'])) { $this->css_minifier = $options['cssMinifier']; } 
     if(isset($options['jsMinifier'])) { $this->js_minifier = $options['jsMinifier']; } 
    } 
    public function process() { 
     if ($this->is_xhtml === null) { $this->is_xhtml = (false !== strpos($this->html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML')); } 
     $this->replacement_hash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']); 
     $this->placeholders = array(); 
     $this->html = preg_replace_callback('/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i', array($this, 'removeScriptCB'), $this->html); 
     $this->html = preg_replace_callback('/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i', array($this, 'removeStyleCB'), $this->html); 
     $this->html = preg_replace_callback('/<!--([\\s\\S]*?)-->/', array($this, 'commentCB'), $this->html); 
     $this->html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i', array($this, 'removePreCB'), $this->html); 
     $this->html = preg_replace_callback('/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i', array($this, 'removeTextareaCB'), $this->html); 
     $this->html = preg_replace('/^\\s+|\\s+$/m', '', $this->html); 
     $this->html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)|ul)\\b[^>]*>)/i', '$1', $this->html); 
     $this->html = preg_replace('/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?</', '>$1$2$3<', $this->html); 
     $this->html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1 $2", $this->html); 
     $this->html = str_replace(array_keys($this->placeholders), array_values($this->placeholders), $this->html); 
     $this->html = str_replace(array_keys($this->placeholders), array_values($this->placeholders), $this->html); 
     return $this->html; 
    } 
    protected function commentCB($m) { return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))?$m[0]:''; } 
    protected function reservePlace($content) { 
     $placeholder = '%' . $this->replacement_hash . count($this->placeholders) . '%'; 
     $this->placeholders[$placeholder] = $content; 
     return $placeholder; 
    } 
    protected function removePreCB($m) { return $this->reservePlace("<pre{$m[1]}"); } 
    protected function removeTextareaCB($m) { return $this->reservePlace("<textarea{$m[1]}"); } 
    protected function removeStyleCB($m) { 
     $open_style = "<style{$m[1]}"; 
     $css  = $m[2]; 
     $css  = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css); 
     $css  = $this->removeCdata($css); 
     $minifier = $this->css_minifier?$this->css_minifier:'trim'; 
     $css  = call_user_func($minifier, $css); 
     return $this->reservePlace($this->needsCdata($css)?"{$open_style}/*<![CDATA[*/{$css}/*]]>*/</style>":"{$open_style}{$css}</style>"); 
    } 
    protected function removeScriptCB($m) { 
     $open_script = "<script{$m[2]}"; 
     $js    = $m[3]; 
     $ws1   = ($m[1] === '')?'':' '; 
     $ws2   = ($m[4] === '')?'':' '; 
     if($this->js_clean_comments) { $js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js); } 
     $js    = $this->removeCdata($js); 
     $minifier  = $this->js_minifier?$this->js_minifier:'trim'; 
     $js    = call_user_func($minifier, $js); 
     return $this->reservePlace($this->needsCdata($js)?"{$ws1}{$open_script}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}":"{$ws1}{$open_script}{$js}</script>{$ws2}"); 
    } 
    protected function removeCdata($str) { return (false !== strpos($str, '<![CDATA['))?str_replace(array('<![CDATA[', ']]>'), '', $str):$str; } 
    protected function needsCdata($str) { return ($this->is_xhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str)); } 
} 

class Minify_CSS { 
    protected $in_hack = false; 
    public static function minify($css) { 
     $min = new self($css); 
     return $min->process(); 
    } 
    private function __construct($css) { 
     $this->css = str_replace("\r\n", "\n", $css); 
     $this->css = str_replace("\r\r", "\n", $this->css); 
     $this->css = str_replace("\n\n", "\n", $this->css); 
    } 
    protected function process() { 
     $this->css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $this->css); 
     $this->css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $this->css); 
     $this->css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $this->css); 
     $this->css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@', array($this, 'commentCB'), $this->css); 
     $this->css = preg_replace('/\\s*{\\s*/', '{', $this->css); 
     $this->css = preg_replace('/;?\\s*}\\s*/', '}', $this->css); 
     $this->css = preg_replace('/\\s*;\\s*/', ';', $this->css); 
     $this->css = preg_replace('/ 
       url\\(  # url(
       \\s* 
       ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis) 
       \\s* 
       \\)   #) 
      /x', 'url($1)', $this->css); 
     $this->css = preg_replace('/ 
       \\s* 
       ([{;])    # 1 = beginning of block or rule separator 
       \\s* 
       ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter) 
       \\s* 
       : 
       \\s* 
       (\\b|[#\'"-])  # 3 = first character of a value 
      /x', '$1$2:$3', $this->css); 
     $this->css = preg_replace_callback('/ 
       (?:    # non-capture 
        \\s* 
        [^~>+,\\s]+ # selector part 
        \\s* 
        [,>+~]  # combinators 
       )+ 
       \\s* 
       [^~>+,\\s]+  # selector part 
       {    # open declaration block 
      /x', array($this, 'selectorsCB'), $this->css); 
     $this->css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i', '$1#$2$3$4$5', $this->css); 
     $this->css = preg_replace_callback('/font-family:([^;}]+)([;}])/', array($this, 'fontFamilyCB'), $this->css); 
     $this->css = preg_replace('/@import\\s+url/', '@import url', $this->css); 
     $this->css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $this->css); 
     $this->css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $this->css); 
     $this->css = preg_replace('/ 
      ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value 
      \\s+ 
      /x' 
       ,"$1 ", $this->css); 
     $this->css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $this->css); 
     return trim($this->css); 
    } 
    protected function selectorsCB($m) { return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]); } 
    protected function commentCB($m) { 
     $has_surrounding_ws = (trim($m[0]) !== $m[1]); 
     $m     = $m[1]; 
     if ($m === 'keep') { return '/**/'; } 
     if ($m === '" "') { return '/*" "*/'; } 
     if (preg_match('@";\\}\\s*\\}/\\*\\[email protected]', $m)) { return '/*";}}/* */'; } 
     if ($this->in_hack) { 
      if (preg_match('@ 
        ^/    # comment started like /*/ 
        \\s* 
        (\\S[\\s\\S]+?) # has at least some non-ws content 
        \\s* 
        /\\*    # ends like /*/ or /**/ 
       @x', $m, $n)) { 
       $this->in_hack = false; 
       return "/*/{$n[1]}/**/"; 
      } 
     } 
     if (substr($m, -1) === '\\') { 
      $this->in_hack = true; 
      return '/*\\*/'; 
     } 
     if ($m !== '' && $m[0] === '/') { 
      $this->in_hack = true; 
      return '/*/*/'; 
     } 
     if ($this->in_hack) { 
      $this->in_hack = false; 
      return '/**/'; 
     } 
     return $has_surrounding_ws?' ':''; 
    } 
    protected function fontFamilyCB($m) { 
     $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 
     $out = 'font-family:'; 
     while (null !== ($piece = array_shift($pieces))) { 
      if ($piece[0] !== '"' && $piece[0] !== "'") { 
       $piece = preg_replace('/\\s+/', ' ', $piece); 
       $piece = preg_replace('/\\s?,\\s?/', ',', $piece); 
      } 
      $out .= $piece; 
     } 
     return $out . $m[2]; 
    } 
} 

class Minify_JS { 
    const IGNORE    = '$1'; 
    private $script    = ''; 
    private $encoding   = 62; 
    private $fast_decode  = true; 
    private $special_chars  = false; 
    private $LITERAL_ENCODING = array(
      'None'   => 0, 
      'Numeric'  => 10, 
      'Normal'  => 62, 
      'High ASCII' => 95 
    ); 
    private $parsers   = array(); 
    private $word_count   = array(); 
    const JSFUNCTION_unpack = 
    'function($packed, $ascii, $count, $keywords, $encode, $decode) { 
    while ($count--) { 
     if ($keywords[$count]) { 
      $packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]); 
     } 
    } 
    return $packed; 
    }'; 
    const JSFUNCTION_decodeBody = 
    ' if (!\'\'.replace(/^/, String)) { 
     // decode all the values we need 
     while ($count--) { 
      $decode[$encode($count)] = $keywords[$count] || $encode($count); 
     } 
     // global replacement function 
     $keywords = [function ($encoded) {return $decode[$encoded]}]; 
     // generic match 
     $encode = function() {return \'\\\\w+\'}; 
     // reset the loop counter - we are now doing a global replace 
     $count = 1; 
    } 
    '; 
    const JSFUNCTIONencode10 = 'function($char_code) { return $char_code; }'; 
    const JSFUNCTIONencode36 = 'function($char_code) { return $char_code.toString(36); }'; 
    const JSFUNCTIONencode62 = 'function($char_code) { return ($char_code < _encoding ? \'\' : arguments.callee(parseInt($char_code/_encoding))) + (($char_code = $char_code % _encoding) > 35 ? String.fromCharCode($char_code + 29) : $char_code.toString(36)); }'; 
    const JSFUNCTIONencode95 = 'function($char_code) { return ($char_code < _encoding ? \'\' : arguments.callee($char_code/_encoding)) + String.fromCharCode($char_code % _encoding + 161); }'; 
    private $buffer; 
    public static function minify($script) { 
     $min = new self($script); 
     return $min->process(); 
    } 
    public function __construct($script, $encoding = 62, $fast_decode = true, $special_chars = false) { 
     $this->script   = $script . "\n"; 
     if (array_key_exists($encoding, $this->LITERAL_ENCODING)) { $encoding = $this->LITERAL_ENCODING[$encoding]; } 
     $this->encoding   = min((int)$encoding, 95); 
     $this->fast_decode  = $fast_decode; 
     $this->special_chars = $special_chars; 
    } 
    public function process() { 
     $this->addParser('basicCompression'); 
     if ($this->special_chars) { $this->addParser('encodeSpecialChars'); } 
     if ($this->encoding) { $this->addParser('encodeKeywords'); } 
     return $this->pack($this->script); 
    } 
    private function pack($script) { 
     for ($i = 0; isset($this->parsers[$i]); $i++) { $script = call_user_func(array(&$this, $this->parsers[$i]), $script); } 
     return $script; 
    } 
    private function addParser($parser) { $this->parsers[] = $parser; } 
    private function basicCompression($script) { 
     $parser = new ParseMaster(); 
     $parser->escapeChar = '\\'; 
     $parser->add('/\'[^\'\\n\\r]*\'/', self::IGNORE); 
     $parser->add('/"[^"\\n\\r]*"/', self::IGNORE); 
     $parser->add('/\\/\\/[^\\n\\r]*[\\n\\r]/', ' '); 
     $parser->add('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\//', ' '); 
     $parser->add('/\\s+(\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?)/', '$2'); 
     $parser->add('/[^\\w\\x24\\/\'"*)\\?:]\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?/', self::IGNORE); 
     if ($this->special_chars) $parser->add('/;;;[^\\n\\r]+[\\n\\r]/'); 
     $parser->add('/\\(;;\\)/', self::IGNORE); 
     $parser->add('/;+\\s*([};])/', '$2'); 
     $script = $parser->exec($script); 
     $parser->add('/(\\b|\\x24)\\s+(\\b|\\x24)/', '$2 $3'); 
     $parser->add('/([+\\-])\\s+([+\\-])/', '$2 $3'); 
     $parser->add('/\\s+/', ''); 
     return $parser->exec($script); 
    } 
    private function encodeSpecialChars($script) { 
     $parser  = new ParseMaster(); 
     $parser->add('/((\\x24+)([a-zA-Z$_]+))(\\d*)/', array('fn' => 'replace_name')); 
     $regexp  = '/\\b_[A-Za-z\\d]\\w*/'; 
     $keywords = $this->_analyze($script, $regexp, 'encodePrivate'); 
     $encoded = $keywords['encoded']; 
     $parser->add($regexp, array('fn' => 'replace_encoded', 'data' => $encoded)); 
     return $parser->exec($script); 
    } 
    private function encodeKeywords($script) { 
     if ($this->encoding > 62) { $script = $this->escape95($script); } 
     $parser  = new ParseMaster(); 
     $encode  = $this->getEncoder($this->encoding); 
     $regexp  = ($this->encoding > 62) ? '/\\w\\w+/' : '/\\w+/'; 
     $keywords = $this->_analyze($script, $regexp, $encode); 
     $encoded = $keywords['encoded']; 
     $parser->add($regexp, array('fn' => 'replace_encoded', 'data' => $encoded)); 
     if (empty($script)) { return $script; } else { return $this->bootStrap($parser->exec($script), $keywords); } 
    } 
    private function _analyze($script, $regexp, $encode) { 
     $all  = array(); 
     preg_match_all($regexp, $script, $all); 
     $sorted  = array(); 
     $encoded = array(); 
     $protected = array(); 
     $all  = $all[0]; 
     if (!empty($all)) { 
      $unsorted   = array(); 
      $protected   = array(); 
      $value    = array(); 
      $this->word_count = array(); 
      $i     = count($all); $j = 0; 
      do { 
       --$i; 
       $word = '$' . $all[$i]; 
       if (!isset($this->word_count[$word])) { 
        $this->word_count[$word] = 0; 
        $unsorted[$j]    = $word; 
        $values[$j]     = call_user_func(array(&$this, $encode), $j); 
        $protected['$' . $values[$j]] = $j++; 
       } 
       $this->word_count[$word]++; 
      } while ($i > 0); 
      $i = count($unsorted); 
      do { 
       $word = $unsorted[--$i]; 
       if (isset($protected[$word])) { 
        $sorted[$protected[$word]]  = substr($word, 1); 
        $protected[$protected[$word]] = true; 
        $this->word_count[$word]  = 0; 
       } 
      } while ($i); 
      usort($unsorted, array(&$this, 'sortWords')); 
      $j = 0; 
      do { 
       if (!isset($sorted[$i])) { $sorted[$i] = substr($unsorted[$j++], 1); } 
       $encoded[$sorted[$i]] = $values[$i]; 
      } while (++$i < count($unsorted)); 
     } 
     return array('sorted' => $sorted, 'encoded' => $encoded, 'protected' => $protected); 
    } 

    private function sortWords($match1, $match2) { return $this->word_count[$match2] - $this->word_count[$match1]; } 
    private function bootStrap($packed, $keywords) { 
     $ENCODE  = $this->safeRegExp('$encode\\($count\\)'); 
     $packed  = "'" . $this->escape($packed) . "'"; 
     $ascii  = min(count($keywords['sorted']), $this->encoding); 
     if ($ascii == 0) { $ascii = 1; } 
     $count  = count($keywords['sorted']); 
     foreach ($keywords['protected'] as $i=>$value) { $keywords['sorted'][$i] = ''; } 
     ksort($keywords['sorted']); 
     $keywords = "'" . implode('|',$keywords['sorted']) . "'.split('|')"; 
     $encode = ($this->encoding > 62) ? 'encode95' : $this->getEncoder($ascii); 
     $encode = $this->getJSFunction($encode); 
     $encode = preg_replace('/_encoding/','$ascii', $encode); 
     $encode = preg_replace('/arguments\\.callee/','$encode', $encode); 
     $inline = '\\$count' . ($ascii > 10 ? '.toString(\\$ascii)' : ''); 
     if ($this->fast_decode) { 
      $decode = $this->getJSFunction('_decodeBody'); 
      if ($this->encoding > 62) { $decode = preg_replace('/\\\\w/', '[\\xa1-\\xff]', $decode); } elseif ($ascii < 36) { $decode = preg_replace($ENCODE, $inline, $decode); } 
      if ($count == 0) { $decode = preg_replace($this->safeRegExp('($count)\\s*=\\s*1'), '$1=0', $decode, 1); } 
     } 
     $unpack = $this->getJSFunction('_unpack'); 
     if ($this->fast_decode) { 
      $this->buffer = $decode; 
      $unpack = preg_replace_callback('/\\{/', array(&$this, 'insertFastDecode'), $unpack, 1); 
     } 
     $unpack = preg_replace('/"/', "'", $unpack); 
     if ($this->encoding > 62) { $unpack = preg_replace('/\'\\\\\\\\b\'\s*\\+|\\+\s*\'\\\\\\\\b\'/', '', $unpack); } 
     if ($ascii > 36 || $this->encoding > 62 || $this->fast_decode) { 
      $this->buffer = $encode; 
      $unpack = preg_replace_callback('/\\{/', array(&$this, 'insertFastEncode'), $unpack, 1); 
     } else { $unpack = preg_replace($ENCODE, $inline, $unpack); } 
     $unpack_packer = new Minify_JS($unpack, 0, false, true); 
     $unpack   = $unpack_packer->process(); 

     $params   = array($packed, $ascii, $count, $keywords); 
     if ($this->fast_decode) { 
      $params[] = 0; 
      $params[] = '{}'; 
     } 
     $params = implode(',', $params); 
     return 'eval(' . $unpack . '(' . $params . "))\n"; 
    } 
    private function insertFastDecode($match) { return '{'.$this->buffer.';'; } 
    private function insertFastEncode($match) { return '{$encode='.$this->buffer.';'; } 
    private function getEncoder($ascii) { return $ascii>10?$ascii>36?$ascii>62?'encode95':'encode62':'encode36':'encode10'; } 
    private function encode10($char_code) { return $char_code; } 
    private function encode36($char_code) { return base_convert($char_code, 10, 36); } 
    private function encode62($char_code) { 
     $res = ''; 
     if ($char_code >= $this->encoding) { $res = $this->encode62((int)($char_code/$this->encoding)); } 
     $char_code = $char_code % $this->encoding; 
     if ($char_code > 35) { return $res . chr($char_code + 29); } else { return $res . base_convert($char_code, 10, 36); } 
    } 
    private function encode95($char_code) { 
     $res = ''; 
     if ($char_code >= $this->encoding) { $res = $this->encode95($char_code/$this->encoding); } 
     return $res . chr(($char_code % $this->encoding) + 161); 
    } 
    private function safeRegExp($string) { return '/'.preg_replace('/\$/', '\\\$', $string).'/'; } 
    private function encodePrivate($char_code) { return "_" . $char_code; } 
    private function escape($script) { return preg_replace('/([\\\\\'])/', '\\\$1', $script); } 
    private function escape95($script) { return preg_replace_callback('/[\\xa1-\\xff]/', array(&$this, 'escape95Bis'), $script); } 
    private function escape95Bis($match) { return '\x'.((string)dechex(ord($match))); } 
    private function getJSFunction($aName) { if (defined('self::JSFUNCTION'.$aName)) { return constant('self::JSFUNCTION'.$aName); } else { return ''; } } 
} 

class ParseMaster { 
    public $ignore_case  = false; 
    public $escape_char  = ''; 
    const EXPRESSION  = 0; 
    const REPLACEMENT  = 1; 
    const LENGTH   = 2; 
    private $GROUPS   = '/\\(/'; 
    private $SUB_REPLACE = '/\\$\\d/'; 
    private $INDEXED  = '/^\\$\\d+$/'; 
    private $TRIM   = '/([\'"])\\1\\.(.*)\\.\\1\\1$/'; 
    private $ESCAPE   = '/\\\./'; 
    private $QUOTE   = '/\'/'; 
    private $DELETED  = '/\\x01[^\\x01]*\\x01/'; 
    private $escaped  = array(); 
    private $patterns  = array(); 
    private $buffer; 
    public function add($expression, $replacement = '') { 
     $length = 1 + preg_match_all($this->GROUPS, $this->internalEscape((string)$expression), $out); 
     if (is_string($replacement)) { 
      if (preg_match($this->SUB_REPLACE, $replacement)) { 
       if (preg_match($this->INDEXED, $replacement)) { $replacement = (int)(substr($replacement, 1)) - 1; } else { 
        $quote   = preg_match($this->QUOTE, $this->internalEscape($replacement))?'"':"'"; 
        $replacement = array('fn' => 'backReferences', 'data' => array('replacement' => $replacement, 'length' => $length, 'quote' => $quote)); 
       } 
      } 
     } 
     if (!empty($expression)) { $this->add_private($expression, $replacement, $length); } else { $this->add_private('/^$/', $replacement, $length); } 
    } 
    public function exec($string) { 
     $this->escaped = array(); 
     $regexp   = '/'; 
     foreach ($this->patterns as $reg) { $regexp .= '(' . substr($reg[self::EXPRESSION], 1, -1) . ')|'; } 
     $regexp   = substr($regexp, 0, -1) . '/'; 
     $regexp .= ($this->ignore_case) ? 'i' : ''; 
     $string   = $this->escape($string, $this->escape_char); 
     $string   = preg_replace_callback($regexp, array(&$this, 'replacement'), $string); 
     $string   = $this->unescape($string, $this->escape_char); 
     return preg_replace($this->DELETED, '', $string); 
    } 
    public function reset() { $this->patterns = array(); } 
    private function add_private() { 
     $arguments   = func_get_args(); 
     $this->patterns[] = $arguments; 
    } 
    private function replacement($arguments) { 
     if (empty($arguments)) { return ''; } 
     $i = 1; $j = 0; 
     while (isset($this->patterns[$j])) { 
      $pattern = $this->patterns[$j++]; 
      if (isset($arguments[$i]) && ($arguments[$i] != '')) { 
       $replacement = $pattern[self::REPLACEMENT]; 
       if (is_array($replacement) && isset($replacement['fn'])) { 
        if (isset($replacement['data'])) $this->buffer = $replacement['data']; 
        return call_user_func(array(&$this, $replacement['fn']), $arguments, $i); 
       } elseif (is_int($replacement)) { return $arguments[$replacement + $i]; } 
       $delete = ($this->escape_char == '' || strpos($arguments[$i], $this->escape_char) === false) ? '' : "\x01" . $arguments[$i] . "\x01"; 
       return $delete . $replacement; 
      } else { $i += $pattern[self::LENGTH]; } 
     } 
    } 
    private function backReferences($match, $offset) { 
     $replacement = $this->buffer['replacement']; 
     $quote   = $this->buffer['quote']; 
     $i    = $this->buffer['length']; 
     while ($i) { $replacement = str_replace('$'.$i--, $match[$offset + $i], $replacement); } 
     return $replacement; 
    } 
    private function replace_name($match, $offset){ 
     $length   = strlen($match[$offset + 2]); 
     $start   = $length - max($length - strlen($match[$offset + 3]), 0); 
     return substr($match[$offset + 1], $start, $length) . $match[$offset + 4]; 
    } 
    private function replace_encoded($match, $offset) { return $this->buffer[$match[$offset]]; } 
    private function escape($string, $escape_char) { 
     if ($escape_char) { 
      $this->buffer = $escape_char; 
      return preg_replace_callback('/\\' . $escape_char . '(.)' .'/', array(&$this, 'escapeBis'), $string); 
     } else { return $string; } 
    } 
    private function escapeBis($match) { 
     $this->escaped[] = $match[1]; 
     return $this->buffer; 
    } 
    private function unescape($string, $escape_char) { 
     if ($escape_char) { 
      $regexp = '/'.'\\'.$escape_char.'/'; 
      $this->buffer = array('escapeChar'=> $escape_char, 'i' => 0); 
      return preg_replace_callback($regexp, array(&$this, 'unescapeBis'), $string); 
     } else { return $string; } 
    } 
    private function unescapeBis() { 
     if (isset($this->escaped[$this->buffer['i']])&& $this->escaped[$this->buffer['i']] != '') { $temp = $this->escaped[$this->buffer['i']]; } else { $temp = ''; } 
     $this->buffer['i']++; 
     return $this->buffer['escapeChar'] . $temp; 
    } 
    private function internalEscape($string) { return preg_replace($this->ESCAPE, '', $string); } 
} 
関連する問題