@php // 判题卡项目:保留题号与题目对应方框数(用于OCR锚点+判卷标记) $scanSheetItems = []; $countBlanks = function ($text) { $text = (string)$text; // 与判卷正文保持一致:下划线、中文空括号、英文空括号 $count = 0; $count += preg_match_all('/_{2,}/u', $text, $m); $count += preg_match_all('/(\s*)/u', $text, $m); $count += preg_match_all('/\(\s*\)/', $text, $m); return max(1, $count); }; $countSteps = function ($text) { $text = (string)$text; // 与判卷正文保持一致:支持“步骤1”与“第1步”两种写法 $count = preg_match_all('/(步骤\s*\d+|第\s*\d+\s*步)/u', $text, $m); return max(1, $count); }; foreach (($questions['choice'] ?? []) as $q) { $scanSheetItems[] = ['no' => (int)($q->question_number ?? 0), 'box_count' => 1]; } foreach (($questions['fill'] ?? []) as $q) { $scanSheetItems[] = ['no' => (int)($q->question_number ?? 0), 'box_count' => $countBlanks($q->content ?? '')]; } foreach (($questions['answer'] ?? []) as $q) { $scanSheetItems[] = ['no' => (int)($q->question_number ?? 0), 'box_count' => $countSteps($q->solution ?? '')]; } usort($scanSheetItems, function ($a, $b) { return ($a['no'] <=> $b['no']); }); // 每页容量不是上限20,而是保证至少可容纳20题,并尽量提高单页承载 $scanSheetPerPage = 24; $scanSheetPages = array_chunk($scanSheetItems, $scanSheetPerPage); @endphp @foreach($scanSheetPages as $pageIndex => $scanSheetPageItems)