src/Leevel/View/Parser.php
protected function getPosition(string $content, string $find, int $start): array
    {
        /*
         *
         * ======= start =======
         *
         * {tagself}
         * yes
         * {/tagself}
         *
         * ======== end =======
         *
         * Array
         * (
         * [start] => 27
         * [end] => 64
         * [start_line] => 2
         * [end_line] => 4
         * [start_in] => 2
         * [end_in] => 17
         * )
         */
        $data = [];

        // 空
        if (empty($find)) {
            $data['start'] = -1;
            $data['end'] = -1;
            $data['start_line'] = -1;
            $data['end_line'] = -1;
            $data['start_in'] = -1;
            $data['end_in'] = -1;

            return $data;
        }

        $total = strlen($content);

        // 起止字节位置
        $start = strpos($content, $find, $start);
        $end = $start + strlen($find) - 1;

        // 起止行数
        $startLine = $start <= 0 ? 0 : substr_count($content, "\n", 0, $start);
        $endLine = $end <= 0 ? 0 : substr_count($content, "\n", 0, $end);

        /**
         * 匹配模块范围圈（在这个字节里面的都是它的子模快）
         * 找到开始和结束的地方就确定了这个模块所在区域范围.
         */

        // 起点的行首换行位置 && 结束点的行首位置
        $lineStartFirst = strrpos(substr($content, 0, $start), "\n") + 1;
        $lineEndFirst = strrpos(substr($content, 0, $end), "\n") + 1;
        $startIn = $start - $lineStartFirst;
        $endIn = $end - $lineEndFirst;

        // 返回结果
        $data['start'] = $start;
        $data['end'] = $end;
        $data['start_line'] = $startLine;
        $data['end_line'] = $endLine;
        $data['start_in'] = $startIn;
        $data['end_in'] = $endIn;

        return $data;
    }
protected function getPosition(string $content, string $find, int $start): array
    {
        /*
         *
         * ======= start =======
         *
         * {tagself}
         * yes
         * {/tagself}
         *
         * ======== end =======
         *
         * Array
         * (
         * [start] => 27
         * [end] => 64
         * [start_line] => 2
         * [end_line] => 4
         * [start_in] => 2
         * [end_in] => 17
         * )
         */
        $data = [];

        // 空
        if (empty($find)) {
            $data['start'] = -1;
            $data['end'] = -1;
            $data['start_line'] = -1;
            $data['end_line'] = -1;
            $data['start_in'] = -1;
            $data['end_in'] = -1;

            return $data;
        }

        $total = strlen($content);

        // 起止字节位置
        $start = strpos($content, $find, $start);
        $end = $start + strlen($find) - 1;

        // 起止行数
        $startLine = $start <= 0 ? 0 : substr_count($content, "\n", 0, $start);
        $endLine = $end <= 0 ? 0 : substr_count($content, "\n", 0, $end);

        /**
         * 匹配模块范围圈（在这个字节里面的都是它的子模快）
         * 找到开始和结束的地方就确定了这个模块所在区域范围.
         */

        // 起点的行首换行位置 && 结束点的行首位置
        $lineStartFirst = strrpos(substr($content, 0, $start), "\n") + 1;
        $lineEndFirst = strrpos(substr($content, 0, $end), "\n") + 1;
        $startIn = $start - $lineStartFirst;
        $endIn = $end - $lineEndFirst;

        // 返回结果
        $data['start'] = $start;
        $data['end'] = $end;
        $data['start_line'] = $startLine;
        $data['end_line'] = $endLine;
        $data['start_in'] = $startIn;
        $data['end_in'] = $endIn;

        return $data;
    }
分析匹配标签的位置.

@param string $content 待编译的模板
@param string $find    匹配的标签
@param int    $start   起始查找的位置

@return array start 标签开始的位置（字节数）
@note int end 标签结束的位置（字节数）
@notenote int start_line 标签开始的行（行数）
@note int end_line 标签结束的行（行数）
@note int start_in 标签开始的所在的行的起始字节数
@note int end_in 标签结束的所在的行的起始字节数