|
2 | 2 |
|
3 | 3 | import org.springframework.util.StringUtils; |
4 | 4 |
|
| 5 | +import java.util.ArrayList; |
5 | 6 | import java.util.Collections; |
6 | 7 | import java.util.LinkedHashMap; |
7 | 8 | import java.util.List; |
|
12 | 13 |
|
13 | 14 | /** |
14 | 15 | * Bangumi wiki 原始字符串(infobox)解析工具。 |
15 | | - * |
16 | | - * <pre> |
17 | | - * 输入示例: |
18 | | - * {{Infobox animanga/TVAnime |
19 | | - * |中文名= 呪術廻戦 |
20 | | - * |话数= 24 |
21 | | - * |放送开始= 2020年10月2日 |
22 | | - * |导演= 朴性厚 |
23 | | - * |原作= 芥見下々 |
24 | | - * |人物设定= 平松禎史 |
25 | | - * }} |
26 | | - * |
27 | | - * 输出 info 示例: "24话 / 2020年10月2日 / 朴性厚 / 芥見下々 / 平松禎史" |
28 | | - * </pre> |
29 | 16 | */ |
30 | 17 | public final class InfoboxParser { |
31 | 18 |
|
@@ -88,4 +75,62 @@ public static String toInfo(String infobox) { |
88 | 75 | .filter(StringUtils::hasText) |
89 | 76 | .collect(Collectors.joining(" / ")); |
90 | 77 | } |
| 78 | + |
| 79 | + /** |
| 80 | + * 将 infobox wiki 字符串解析为 key → 多值列表,同时处理单行和多行({…})值。 |
| 81 | + * <pre> |
| 82 | + * 单行:|话数= 25 → "话数" → ["25"] |
| 83 | + * 多行:|别名={ → "别名" → ["叛逆的鲁路修R2", "Code Geass: ..."] |
| 84 | + * [叛逆的鲁路修R2] |
| 85 | + * [Code Geass: ...] |
| 86 | + * } |
| 87 | + * </pre> |
| 88 | + */ |
| 89 | + public static Map<String, List<String>> toEntries(String infobox) { |
| 90 | + if (!StringUtils.hasText(infobox)) { |
| 91 | + return Collections.emptyMap(); |
| 92 | + } |
| 93 | + Map<String, List<String>> entries = new LinkedHashMap<>(); |
| 94 | + String[] lines = infobox.split("\\R"); |
| 95 | + String currentKey = null; |
| 96 | + boolean inBlock = false; |
| 97 | + |
| 98 | + for (String line : lines) { |
| 99 | + String trimmed = line.trim(); |
| 100 | + if (trimmed.equals("}}")) { |
| 101 | + break; |
| 102 | + } |
| 103 | + if (trimmed.startsWith("{{")) { |
| 104 | + continue; |
| 105 | + } |
| 106 | + if (inBlock) { |
| 107 | + if (trimmed.equals("}")) { |
| 108 | + inBlock = false; |
| 109 | + currentKey = null; |
| 110 | + continue; |
| 111 | + } |
| 112 | + // 多行值:去掉首尾的 [ ] |
| 113 | + if (trimmed.startsWith("[") && trimmed.endsWith("]")) { |
| 114 | + String v = trimmed.substring(1, trimmed.length() - 1).trim(); |
| 115 | + if (!v.isEmpty()) { |
| 116 | + entries.get(currentKey).add(v); |
| 117 | + } |
| 118 | + } |
| 119 | + continue; |
| 120 | + } |
| 121 | + Matcher m = INFOBOX_LINE.matcher(trimmed); |
| 122 | + if (m.matches()) { |
| 123 | + currentKey = m.group(1).trim(); |
| 124 | + String value = m.group(2).trim(); |
| 125 | + if (value.equals("{")) { |
| 126 | + inBlock = true; |
| 127 | + entries.put(currentKey, new ArrayList<>()); |
| 128 | + } else { |
| 129 | + entries.put(currentKey, new ArrayList<>(List.of(value))); |
| 130 | + currentKey = null; |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + return Collections.unmodifiableMap(entries); |
| 135 | + } |
91 | 136 | } |
0 commit comments