RomanNumeralHelper
整数与罗马数字互转
基本信息
| 属性 | 值 |
|---|---|
| 路径 | squeek.tictooltips.helpers.RomanNumeralHelper |
| 行数 | 61 |
| 源码注释 | 改编自两个 StackOverflow 答案(:5) |
两张字典(static 初始化)
字符 → 值(:9-17):
| I | V | X | L | C | D | M |
|---|---|---|---|---|---|---|
| 1 | 5 | 10 | 50 | 100 | 500 | 1000 |
值 → 罗马串(:19-32),TreeMap(键升序,13 项):
| 键 | 值 | 键 | 值 | 键 | 值 | 键 | 值 |
|---|---|---|---|---|---|---|---|
| 1000 | M |
900 | CM |
500 | D |
400 | CD |
| 100 | C |
50 | L |
40 | XL |
10 | X |
| 9 | IX |
5 | V |
4 | IV |
1 | I |
含全部 6 个减法写法(CM CD XL IX IV),标准写法。
toRoman(:34-40)—— 递归
int key = NumberRomanDictionary.floorKey(number);
if (number == key) return NumberRomanDictionary.get(key);
return NumberRomanDictionary.get(key) + toRoman(number - key);
用 floorKey 取不超过 number 的最大键,然后递归处理余数。
⚠️ number < 1 时抛异常:TreeMap.floorKey(0) / floorKey(-5) 返回 null,
NumberRomanDictionary.get(null) 抛 NullPointerException。
调用方 StringHelper 的 getReinforcedString 用
if (reinforced > 9) return ...unbreakable 把 >= 10 挡掉了,
所以实际只会传 0-9。但 toRoman(0) 也会抛 ——
floorKey(0) 在这张表里返回 null(最小键是 1),
所以强化等级 0 的工具会崩。
不过 getReinforcedString 只在 mat.reinforced() > 0 时被调用
(TooltipHandler.java:278),实际路径上 0 不会进来。
fromRoman(:42-59)—— 迭代
⚠️ 逆转换用了一个非常规写法:不是标准的「小值在大值前则减」, 而是 subtract 整个差值再回加:
if (previous != 0 && current > previous) total = total - (2 * previous) + current;
else total += current;
total - 2*previous + current 等价于「减去 previous 的两次再补 current」,
在标准减法记法下是正确的(IX:+1 然后 -2*1+10 = 9)。
两处实际缺陷
-
:49的previous初值是字符'\0'而非0:previous = previousRoman != '\0' ? RomanNumberDictionary.get(previousRoman) : '\0';
三元表达式的 else 分支给
int previous赋了字符字面量'\0'(值为 0)。 数值上恰好等于想要的 0,但类型不匹配(char 隐式转 int),属于会误导读者的写法。 -
未知字符抛 NPE ——
RomanNumberDictionary.get(currentRoman)对 不在字典里的字符(如小写i、空格)返回null,total += current处自动拆箱null→NullPointerException。fromRoman没有大小写归一化,传小写罗马数字必崩。
fromRoman 无调用点
grep 全仓,fromRoman 在本 mod 内没有任何调用,
只有 toRoman 被 StringHelper 使用。
它是为对称性保留的未使用 API —— 且 apiPackage 在
gradle.properties 中为空,不对外暴露。
相关
- StringHelper - 唯一实际调用方(
getReinforcedString)