'root', 'content' => []]; $buffer = ''; $dqOpen = false; $sqOpen = false; $counter = 1000000; while (!feof($f)) { $input = fread($f, 20480); while ($input) { $pos = [ 'open' => strpos($input, '{'), 'close' => strpos($input, '}'), 'end' => strpos($input, ';'), 'sq' => strpos($input, "'"), 'dq' => strpos($input, '"'), ]; $pos = array_filter($pos, 'is_numeric'); if (!$pos) { $buffer .= $input; $input = false; continue; } asort($pos); $firstPos = reset($pos); switch (key($pos)) { case 'open': $row = $buffer . substr($input, 0, $firstPos); $buffer = ''; $input = substr($input, $firstPos + 1); if ($current) { $stack[] = $current; } $current = (object) [ 'type' => 'block', 'key' => trim($row), 'content' => [], ]; break; case 'close': $row = trim($buffer . substr($input, 0, $firstPos)); $buffer = ''; $input = substr($input, $firstPos + 1); if (!$current || !$stack) { throw new \RuntimeException('css closed non-open block'); } if ($row) { $sortValue = trim(strstr($row, ':', true)) . '-' . $counter++; $current->content[$sortValue] = $row . ';'; } asort($current->content); $old = $current; $current = array_pop($stack); $prefix = in_array($old->key[0], ['#', '.']) ? '' : '*'; $current->content[$prefix . $old->key . '-' . $counter++] = $old->key . ' {' . PHP_EOL . "\t" . trim (str_replace("\n", "\n\t", implode(PHP_EOL, $old->content))) . PHP_EOL . '}' . PHP_EOL; break; case 'end': $row = $buffer . substr($input, 0, $firstPos + 1); $buffer = ''; $input = substr($input, $firstPos + 1); if (!$current || $current->type === 'root') { throw new \RuntimeException('css outside block: ' . $row); } $sortValue = '~' . trim(strstr($row, ':', true)) . '-' . $counter++; $current->content[$sortValue] = trim($row); break; case 'sq': $buffer .= substr($input, 0, $firstPos + 1); $input = substr($input, $firstPos + 1); $sqOpen = !$sqOpen; break; case 'dq': $buffer .= substr($input, 0, $firstPos + 1); $input = substr($input, $firstPos + 1); $dqOpen = !$dqOpen; break; default: die('unknown key'); } } } fclose($f); if (trim($buffer)) { throw new \RuntimeException('Unexpected end of file: ' . $buffer); } if (!$current || $stack || $current->type !== 'root') { throw new \RuntimeException('Wrong number of blocks closed. stack size: ' . count($stack)); } asort($current->content); echo implode(PHP_EOL, $current->content); }