diff --git a/web/reinfo.php b/web/reinfo.php index 37f88a7..58ae83e 100644 --- a/web/reinfo.php +++ b/web/reinfo.php @@ -102,6 +102,104 @@ function dedup_runtimeinfo($text, &$dedup_count) { return implode("\n", $out); } +/** + * 把 runtimeinfo.error 解析为结构化的 diff blocks + * 返回 [['name' => 'test1.out', 'expected' => [...], 'yours' => [...], 'full_mode' => bool], ...] + * 解析失败返回空数组 + */ +function parse_diff_blocks($text) { + $blocks = array(); + if (empty($text)) return $blocks; + + // 先按 "\n\n" 切分(simple mode 每个测试点之间有空行) + $chunks = preg_split('/\n\s*\n/', $text); + foreach ($chunks as $chunk) { + $chunk = trim($chunk); + if ($chunk === '') continue; + + // full mode: 形如 "========[test1.out]=========" 开头 + if (preg_match('/^=+\[([^\]]+)\]=+$/m', $chunk, $m_head)) { + $name = $m_head[1]; + // 提取 "------diff out 200 lines-----" 后面的内容 + if (preg_match('/------diff out[^\n]*-+\n(.*?)\n=+\s*$/s', $chunk, $m_diff)) { + $diff_text = trim($m_diff[1]); + } else { + continue; + } + $lines = parse_diff_side_by_side($diff_text); + if (!empty($lines)) { + $blocks[] = array( + 'name' => $name, + 'expected' => $lines['expected'], + 'yours' => $lines['yours'], + 'full_mode' => true, + ); + } + continue; + } + + // simple mode: 形如 "test1.out\n--\n|Expected|Yours\n|--|--\n|..." + if (preg_match('/^([^\n|]+)\n--\n\|Expected\|Yours\n\|--\|--\n(.*)$/s', $chunk, $m)) { + $name = trim($m[1]); + $table = $m[2]; + $lines = parse_pipe_diff_table($table); + if (!empty($lines)) { + $blocks[] = array( + 'name' => $name, + 'expected' => $lines['expected'], + 'yours' => $lines['yours'], + 'full_mode' => false, + ); + } + } + } + return $blocks; +} + +/** + * 解析 "|expected|yours\n" 格式的表格 + */ +function parse_pipe_diff_table($text) { + $expected = array(); + $yours = array(); + $lines = explode("\n", $text); + foreach ($lines as $line) { + if (strlen($line) < 2 || $line[0] !== '|') continue; + $rest = substr($line, 1); + $pos = strpos($rest, '|'); + if ($pos === false) continue; + $left = substr($rest, 0, $pos); + $right = substr($rest, $pos + 1); + $expected[] = $left; + $yours[] = $right; + } + if (empty($expected)) return array(); + return array('expected' => $expected, 'yours' => $yours); +} + +/** + * 解析 `diff -y` 格式: " < expected > yours" 或 " expected | yours" + */ +function parse_diff_side_by_side($text) { + $expected = array(); + $yours = array(); + $lines = explode("\n", $text); + foreach ($lines as $line) { + if (preg_match('/^(.*?)\s+[<>|]\s+(.*)$/', $line, $m)) { + $expected[] = $m[1]; + $yours[] = $m[2]; + } elseif (trim($line) === '') { + // 空行:两边都空 + } else { + // 单边(一边空):整行属于另一边 + $expected[] = $line; + $yours[] = ''; + } + } + if (empty($expected)) return array(); + return array('expected' => $expected, 'yours' => $yours); +} + $view_reinfo = ""; $view_reinfo_raw = ""; // 原始(管理员/有权限者看) $view_reinfo_summary = ""; // 折叠后(普通用户看) @@ -215,111 +313,6 @@ if($ok){ } } -/** - * 把 runtimeinfo.error 解析为结构化的 diff blocks - * 返回 [['name' => 'test1.out', 'expected' => [...], 'yours' => [...], 'full_mode' => bool], ...] - * 解析失败返回空数组 - */ -function parse_diff_blocks($text) { - $blocks = array(); - if (empty($text)) return $blocks; - - // 先按 "\n\n" 切分(simple mode 每个测试点之间有空行) - // 但要避免切分 full mode 里的内容 - $chunks = preg_split('/\n\s*\n/', $text); - foreach ($chunks as $chunk) { - $chunk = trim($chunk); - if ($chunk === '') continue; - - // full mode: 形如 "========[test1.out]=========" 开头 - if (preg_match('/^=+\[([^\]]+)\]=+$/m', $chunk, $m_head)) { - $name = $m_head[1]; - // 提取 "------diff out 200 lines-----" 后面的内容 - if (preg_match('/------diff out[^\n]*-+\n(.*?)\n=+\s*$/s', $chunk, $m_diff)) { - $diff_text = trim($m_diff[1]); - } else { - continue; // 没找到 diff 段,跳过 - } - $lines = parse_diff_side_by_side($diff_text); - if (!empty($lines)) { - $blocks[] = array( - 'name' => $name, - 'expected' => $lines['expected'], - 'yours' => $lines['yours'], - 'full_mode' => true, - ); - } - continue; - } - - // simple mode: 形如 "test1.out\n--\n|Expected|Yours\n|--|--\n|..." - if (preg_match('/^([^\n|]+)\n--\n\|Expected\|Yours\n\|--\|--\n(.*)$/s', $chunk, $m)) { - $name = trim($m[1]); - $table = $m[2]; - $lines = parse_pipe_diff_table($table); - if (!empty($lines)) { - $blocks[] = array( - 'name' => $name, - 'expected' => $lines['expected'], - 'yours' => $lines['yours'], - 'full_mode' => false, - ); - } - } - } - return $blocks; -} - -/** - * 解析 "|expected|yours\n" 格式的表格 - * 已知边角:每行以 | 开头和 | 分隔;空字段表示没有该行 - */ -function parse_pipe_diff_table($text) { - $expected = array(); - $yours = array(); - $lines = explode("\n", $text); - foreach ($lines as $line) { - if (strlen($line) < 2 || $line[0] !== '|') continue; - // 形如 "|a|b" 拆出 a 和 b - $rest = substr($line, 1); - // 找第一个 | - $pos = strpos($rest, '|'); - if ($pos === false) continue; - $left = substr($rest, 0, $pos); - $right = substr($rest, $pos + 1); - $expected[] = $left; - $yours[] = $right; - } - if (empty($expected)) return array(); - return array('expected' => $expected, 'yours' => $yours); -} - -/** - * 解析 `diff -y` 格式: " < expected > yours" - * 中间用 | 或 / 分隔(取决于 GNU diff 版本) - */ -function parse_diff_side_by_side($text) { - $expected = array(); - $yours = array(); - $lines = explode("\n", $text); - foreach ($lines as $line) { - // 找中间的 | 或 / (GNU diff -y 格式) - // 形如 " line1 | line2 " 或 " line1 < line2 " - if (preg_match('/^(.*?)\s+[<>|]\s+(.*)$/', $line, $m)) { - $expected[] = $m[1]; - $yours[] = $m[2]; - } elseif (trim($line) === '') { - // 空行:两边都空 - } else { - // 单边(一边空):整行属于另一边 - $expected[] = $line; - $yours[] = ''; - } - } - if (empty($expected)) return array(); - return array('expected' => $expected, 'yours' => $yours); -} - // 不是本人的提交,且不是 source_browser else{ if($spj[0][0]!=2) $view_errors = $MSG_WARNING_ACCESS_DENIED;