目標標籤格式
{dede:tag attr='val' attr2="val2"} ... {/dede:tag}
{dede:tag attr='val' /}
{dede:global.name /}
{dede:field.name function='html2text(@me)' /}
{dede:include filename='header.htm' /}
核心正則(支持遞歸嵌套)
$pattern = '/
( # 整體捕獲組 1
\{dede: # 起始標記
[^{}]* # 標籤名+屬性(不含大括號)
(?: # 非捕獲組:兩種結束方式
\/ # 自閉合 />
| # 或
\} # 閉合 > 進入內容
(?: # 內容部分(遞歸)
[^{}]* # 非標籤文本
| # 或
(?R) # 遞歸匹配整個模式(嵌套標籤)
)*
\{/dede: # 結束標記
[^{}]* # 標籤名
\}
)
)
/x';
preg_match_all($pattern, $template, $matches);
解析邏輯(提取標籤名、屬性、函數、內容)
function parse_dede_tags(string $tpl): array {
$tags = [];
$pattern = '/\{dede:([^}\s\/]+)\s*([^}]*)\}(.*?)\{\/dede:\\1\}|\{dede:([^}\s\/]+)\s*([^}]*)\/\}/s';
// 簡化版,實際建議用上述遞歸正則
preg_match_all($pattern, $tpl, $m, PREG_SET_ORDER);
foreach ($m as $match) {
if (!empty($match[1])) { // 雙標籤
[$full, $tag, $attrs, $content] = [$match[0], $match[1], $match[2], $match[3]];
} else { // 自閉合
[$full, $tag, $attrs] = [$match[0], $match[4], $match[5]];
$content = '';
}
$attrArr = [];
preg_match_all('/(\w+)\s*=\s*([\'"])(.*?)\\2/', $attrs, $am, PREG_SET_ORDER);
foreach ($am as $a) {
$attrArr[$a[1]] = $a[3];
if ($a[1] === 'function') $func = $a[3];
}
$tags[] = [
'raw' => $full,
'tag' => $tag,
'attrs' => $attrArr,
'function' => $func ?? null,
'content' => $content,
];
}
return $tags;
}
輸出示例
[
'raw' => "{dede:list pagesize='10'}{dede:field.title/}{/dede:list}",
'tag' => 'list',
'attrs' => ['pagesize' => '10'],
'function' => null,
'content' => "{dede:field.title/}"
]
注意事項
- 正則性能:極大模板(>1MB)遞歸正則可能回溯過深,建議分塊解析或用狀態機/解析器生成器(如 PHP-Parser 改造)。
- 屬性值含引號轉義:
function='html2text(@me)' 內單引號需處理。
- 編碼統一:模板文件讀取時指定
mb_convert_encoding($tpl, 'UTF-8', 'GBK')。