|
|
@@ -56,8 +56,9 @@ public class DanReportParseService {
|
|
|
for (String line : lines) {
|
|
|
String trimmed = line.trim();
|
|
|
if (!trimmed.isEmpty()) {
|
|
|
- // 去除PDF提取中的特殊Unicode字符
|
|
|
- trimmed = trimmed.replaceAll("[\\uF000-\\uFFFF]", "").trim();
|
|
|
+ // 去除PDF提取中的特殊Unicode字符(仅保留真正私用区 U+E000–U+F8FF,
|
|
|
+ // 避免误删全角冒号 U+FF1A 等常用 CJK 标点导致「姓名:俊辰」→「姓名俊辰」)
|
|
|
+ trimmed = trimmed.replaceAll("[\\uE000-\\uF8FF]", "").trim();
|
|
|
if (!trimmed.isEmpty()) {
|
|
|
lineList.add(trimmed);
|
|
|
}
|
|
|
@@ -215,7 +216,12 @@ public class DanReportParseService {
|
|
|
StringBuilder suggestions = new StringBuilder();
|
|
|
|
|
|
// 1. 基本信息和日期
|
|
|
- String reportDate = findFieldValue(lines, "测评日期", "报告日期", "评估日期");
|
|
|
+ String reportDate = findFieldValue(lines, "测评日期", "报告日期", "评估日期", "测试日期");
|
|
|
+ if (reportDate == null) {
|
|
|
+ // 降级版式兜底: "测试日期:2026-07-03" 等自由文本中的日期字段
|
|
|
+ java.util.regex.Matcher dateFallback = Pattern.compile("测?试日期[::]\\s*(\\d{4}[-/]\\d{1,2}[-/]\\d{1,2})").matcher(fullText);
|
|
|
+ if (dateFallback.find()) reportDate = dateFallback.group(1);
|
|
|
+ }
|
|
|
String name = findFieldValue(lines, "姓名", "学生姓名", "被评估人");
|
|
|
extra.put("name", name);
|
|
|
extra.put("reportDate", reportDate);
|
|
|
@@ -258,6 +264,19 @@ public class DanReportParseService {
|
|
|
if (selfConceptStart >= 0) {
|
|
|
int end = mindsetStart > selfConceptStart ? mindsetStart : lines.size();
|
|
|
Map<String, String> selfConcept = parseSelfConcept(lines, selfConceptStart, end);
|
|
|
+ // 降级版式: "自我概念\n自信心 7分\n自尊心 8分"(parseSelfConcept 按「维度 分数」行匹配漏掉带"分"单位)
|
|
|
+ if (selfConcept.isEmpty()) {
|
|
|
+ Pattern confP = Pattern.compile("自信[性心]\\s*(\\d+(?:\\.\\d+)?)");
|
|
|
+ Matcher confM = confP.matcher(fullText);
|
|
|
+ if (confM.find()) {
|
|
|
+ selfConcept.put("自信心", confM.group(1));
|
|
|
+ }
|
|
|
+ Pattern esteemP = Pattern.compile("自尊[性心]?\\s*(\\d+(?:\\.\\d+)?)");
|
|
|
+ Matcher esteemM = esteemP.matcher(fullText);
|
|
|
+ if (esteemM.find()) {
|
|
|
+ selfConcept.put("自尊心", esteemM.group(1));
|
|
|
+ }
|
|
|
+ }
|
|
|
if (!selfConcept.isEmpty()) {
|
|
|
for (Map.Entry<String, String> entry : selfConcept.entrySet()) {
|
|
|
items.add(new DataItem(entry.getKey(), entry.getKey(), entry.getValue(), "selfConcept"));
|
|
|
@@ -353,6 +372,17 @@ public class DanReportParseService {
|
|
|
for (int i = 0; i < cognitiveDims.length; i++) {
|
|
|
String dim = cognitiveDims[i];
|
|
|
String code = dimCodes[i];
|
|
|
+ // 同版式优先: "我的xxx得分 41 | 14%"(分数与百分位在同一行,分隔符为 | 或全角|)
|
|
|
+ Pattern sameLineP = Pattern.compile(
|
|
|
+ "我的" + Pattern.quote(dim) + "得分\\s*(\\d+)\\s*[||]\\s*(\\d+)\\s*%");
|
|
|
+ Matcher sameLineM = sameLineP.matcher(fullText);
|
|
|
+ if (sameLineM.find()) {
|
|
|
+ items.add(new DataItem(code + "_score", dim + "得分", sameLineM.group(1), "cognitive"));
|
|
|
+ extra.put(code + "_score", sameLineM.group(1));
|
|
|
+ items.add(new DataItem(code + "_pct", dim + "百分位", sameLineM.group(2), "cognitive"));
|
|
|
+ extra.put(code + "_pct", sameLineM.group(2));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
int idx = fullText.indexOf("我的" + dim + "得分");
|
|
|
if (idx < 0) continue;
|
|
|
// 跳到下一行
|
|
|
@@ -392,11 +422,11 @@ public class DanReportParseService {
|
|
|
if (!extra.containsKey(code + "_pct")) {
|
|
|
int dimIdx = fullText.indexOf(dim);
|
|
|
if (dimIdx < 0) continue;
|
|
|
- // 在该维度名之后 200 字符内找百分位数字
|
|
|
- int searchEnd = Math.min(dimIdx + 300, fullText.length());
|
|
|
+ // 在该维度名之后 60 字符内找百分位数字(窗口收紧至单维度,避免跨到下一维度)
|
|
|
+ int searchEnd = Math.min(dimIdx + 60, fullText.length());
|
|
|
String window = fullText.substring(dimIdx, searchEnd);
|
|
|
java.util.regex.Matcher pctMatcher =
|
|
|
- Pattern.compile("百分位[((]%[))].*?(\\d+)").matcher(window);
|
|
|
+ Pattern.compile("百分位[((]%[))][^0-9]{0,10}(\\d+)").matcher(window);
|
|
|
if (pctMatcher.find()) {
|
|
|
String val = pctMatcher.group(1);
|
|
|
items.add(new DataItem(code + "_pct", dim + "百分位", val, "cognitive"));
|
|
|
@@ -1673,6 +1703,29 @@ public class DanReportParseService {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ // PDF 抽字常把字段值与下一个字段名粘连(如「俊辰性别:男」):取冒号前的纯汉字片段
|
|
|
+ for (String keyword : keywords) {
|
|
|
+ String compactKw = keyword.replaceAll("\\s+", "");
|
|
|
+ for (String line : lines) {
|
|
|
+ String compact = line.replaceAll("\\s+", "");
|
|
|
+ int idx = compact.indexOf(compactKw + ":");
|
|
|
+ if (idx < 0) idx = compact.indexOf(compactKw + ":");
|
|
|
+ if (idx < 0) continue;
|
|
|
+ String rest = compact.substring(idx + compactKw.length() + 1);
|
|
|
+ if (rest.isEmpty()) continue;
|
|
|
+ // 粘连判定:若同行 value 段内还有分隔符(下一个字段的冒号),
|
|
|
+ // 说明值与后续字段名粘连(PDF 抽字常见「姓 名:俊辰性 别: 男」),截取中间纯汉字段
|
|
|
+ int colon = rest.indexOf(':');
|
|
|
+ if (colon < 0) colon = rest.indexOf(':');
|
|
|
+ if (colon > 0) {
|
|
|
+ String seg = rest.substring(0, colon);
|
|
|
+ Matcher cjk = Pattern.compile("^[\\u4e00-\\u9fa5]{2,8}$").matcher(seg);
|
|
|
+ if (cjk.find()) return seg;
|
|
|
+ }
|
|
|
+ String val = cleanFieldValue(rest);
|
|
|
+ if (val != null && !val.isEmpty()) return val;
|
|
|
+ }
|
|
|
+ }
|
|
|
return null;
|
|
|
}
|
|
|
|