} */ public static function separateStemAndOptions(string $content): array { $contentWithoutSvg = preg_replace('/]*>.*?<\/svg>/is', '[SVG_PLACEHOLDER]', $content); $hasOptions = preg_match('/(?:^|\s)[A-D][\.、:.:]/u', $contentWithoutSvg); if (! $hasOptions) { return [$content, []]; } $options = self::extractOptions($content); if (! empty($options)) { if (preg_match('/^(.+?)(?=(?:^|\s)[A-D][\.、:.:])/su', $contentWithoutSvg, $match)) { $stem = trim($match[1]); if (strpos($stem, '[SVG_PLACEHOLDER]') !== false) { foreach (['A.', 'A、', 'A:', 'A.', 'A:'] as $marker) { if (preg_match('/\s'.preg_quote($marker, '/').'/', $content, $m, PREG_OFFSET_CAPTURE)) { $pos = $m[0][1]; if ($pos > 0) { $stem = trim(mb_substr($content, 0, $pos)); break; } } } } } else { $stem = $content; foreach (['A.', 'A、', 'A:', 'A.', 'A:'] as $marker) { if (preg_match('/\s'.preg_quote($marker, '/').'/', $content, $m, PREG_OFFSET_CAPTURE)) { $pos = $m[0][1]; if ($pos > 0) { $stem = trim(mb_substr($content, 0, $pos)); break; } } } } $stem = preg_replace('/()\s*$/', '', $stem); $stem = trim($stem); return [$stem, $options]; } return [$content, []]; } /** * 与 ExamPdfController::extractOptions 一致 * * @return array */ public static function extractOptions(string $content): array { $options = []; $contentWithoutSvg = preg_replace('/]*>.*?<\/svg>/is', '[SVG_PLACEHOLDER]', $content); $pattern = '/(?:^|\s)([A-D])[\.、:.:]\s*(.+?)(?=(?:^|\s)[A-D][\.、:.:]|$)/su'; if (preg_match_all($pattern, $contentWithoutSvg, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $optionText = trim($match[2]); $optionText = preg_replace('/\s+$/', '', $optionText); $optionText = preg_replace('/^\$\$\s*/', '', $optionText); $optionText = preg_replace('/\s*\$\$$/', '', $optionText); if (! empty($optionText)) { $options[] = $optionText; } } } if (empty($options)) { $lines = preg_split('/[\r\n]+/', $contentWithoutSvg); foreach ($lines as $line) { $line = trim($line); if (preg_match('/^([A-D])[\.、:.:]\s*(.+)$/u', $line, $match)) { $optionText = trim($match[2]); if (! empty($optionText)) { $options[] = $optionText; } } } } return $options; } /** * 与 paper-body 选择题中 $renderedStem 逻辑一致 */ private static function applyBlankPlaceholdersLikeGrading(string $stemLine): string { [$renderedStem] = BlankPlaceholderRenderer::replaceToBlankSpan($stemLine, null, true, false); $renderedStem = BlankPlaceholderRenderer::normalizeTerminalPunctuation($renderedStem, 'remove'); return $renderedStem; } }