java.lang.NullPointerException#Kotlin 原来 Kotlin 里一个 superclass 的 <init> 不能访问到子类的 constructor override val
at NumUnitTrie.getMap(Parser.kt:1199)
at NumUnitPattern.<init>(Parser.kt:1193)
at NumUnitTrie.<init>(Parser.kt:1198)
val n=RepeatUn(asInt(), digitFor('0'..'9')) { it.toString().map { it-'0' } }
val u=KeywordPattern<Int>().apply { mergeStrings("s" to 1, "min" to 60, "hr" to 60*60) }
val k=NumUnitTrie(n, u, IntOps) 我写完了 NumUnits
/tmp/duangsuse.sock
val n=RepeatUn(asInt(), digitFor('0'..'9')) { it.toString().map { it-'0' } } val u=KeywordPattern<Int>().apply { mergeStrings("s" to 1, "min" to 60, "hr" to 60*60) } val k=NumUnitTrie(n, u, IntOps) 我写完了 NumUnits
我来说说,这
1hr1min1s 是累加、三千五百万是更复杂的折叠,因为汉字每个子意群都得带单位。
单位上升(“五百万”)的时候是乘,单位下降(“三千一百”)的时候是加,其实不必递归。
汉字没有 123 这种直接的数字(都是一百二十三)所以一个单位的显示还得递归地去做。
这个 show,不需要区分仅个位或大于十的情况,直接交给能输出数字的子程序即可。
NumUnit 已经做好了这一点,可它做不到最大单位也无法仅含个位情况下的递归输出。
而且如果 units 规则指定不对(间隔没在进制以内),也可能出现非仅存个位的情况,不过我觉得我不会出这个问题
关键是对于任何一位的内部数字显示,都必须是递归的…… 这一点我还没有打算
汉字的特例也就是 10 until 20 的 “十一” “十二” 无需带单位的情况了,这种情况下“十”作为数字起始部分特殊处理
还有
1hr1min1s 和 三千五百万 有啥区别。1hr1min1s 是累加、三千五百万是更复杂的折叠,因为汉字每个子意群都得带单位。
单位上升(“五百万”)的时候是乘,单位下降(“三千一百”)的时候是加,其实不必递归。
汉字没有 123 这种直接的数字(都是一百二十三)所以一个单位的显示还得递归地去做。
这个 show,不需要区分仅个位或大于十的情况,直接交给能输出数字的子程序即可。
NumUnit 已经做好了这一点,可它做不到最大单位也无法仅含个位情况下的递归输出。
而且如果 units 规则指定不对(间隔没在进制以内),也可能出现非仅存个位的情况,不过我觉得我不会出这个问题
关键是对于任何一位的内部数字显示,都必须是递归的…… 这一点我还没有打算
汉字的特例也就是 10 until 20 的 “十一” “十二” 无需带单位的情况了,这种情况下“十”作为数字起始部分特殊处理
还有
一千零一,如果两个单位之间不止差一个阶层就得加“零”,这个我还没想好
/tmp/duangsuse.sock
我来说说,这 1hr1min1s 和 三千五百万 有啥区别。 1hr1min1s 是累加、三千五百万是更复杂的折叠,因为汉字每个子意群都得带单位。 单位上升(“五百万”)的时候是乘,单位下降(“三千一百”)的时候是加,其实不必递归。 汉字没有 123 这种直接的数字(都是一百二十三)所以一个单位的显示还得递归地去做。 这个 show,不需要区分仅个位或大于十的情况,直接交给能输出数字的子程序即可。 NumUnit 已经做好了这一点,可它做不到最大单位也无法仅含个位情况下的递归输出。 而且如果 units…
This media is not supported in your browser
VIEW IN TELEGRAM
欸我有了一个主意,ParserKt 的 number show 可以基于 unfold 的去做,那么这个 toString 的流程是可以随便指定的
只要我能够 lateinit var 引用 numUnit 的实例,就可以做到递归 show 出汉字单位前的数值了
只要我能够 lateinit var 引用 numUnit 的实例,就可以做到递归 show 出汉字单位前的数值了
/tmp/duangsuse.sock
我来说说,这 1hr1min1s 和 三千五百万 有啥区别。 1hr1min1s 是累加、三千五百万是更复杂的折叠,因为汉字每个子意群都得带单位。 单位上升(“五百万”)的时候是乘,单位下降(“三千一百”)的时候是加,其实不必递归。 汉字没有 123 这种直接的数字(都是一百二十三)所以一个单位的显示还得递归地去做。 这个 show,不需要区分仅个位或大于十的情况,直接交给能输出数字的子程序即可。 NumUnit 已经做好了这一点,可它做不到最大单位也无法仅含个位情况下的递归输出。 而且如果 units…
我们常说,个、十、百、千、万、十万、百万、千万、亿、十亿、百亿、千亿、万亿、亿亿,可是这么枚举下去可以到 "亿亿亿亿亿亿",何时是个头呢?到 Int.MAX_VALUE 那不是一个正经程序员会做的权变。
所以不能滥用字典树的操作,只有十百千万亿,没有组合单位。
所以不能滥用字典树的操作,只有十百千万亿,没有组合单位。
val hanDigit = MapPattern(mapOf(
*"一二三四五六七八九".asIterable().zip(1..9).toArray())
)
val hanUnit = KeywordPattern<Int>().apply {
mergeStrings("" to 1, "十" to 10, "百" to 100)
mergeStrings("千" to 1000, "万" to 10000)
} >>> val k=NumUnitTrie(hanDigit, hanUnit, IntOps)
>>> k.read("一百一十")
res31: kotlin.Int? = 110>>> k.read("一百一十一")
res32: kotlin.Int? = null>>> k.rebuild("一百一十")
res33: kotlin.String? = 一百一十哈,可是碰到 “三十二万” 就犯难了
/tmp/duangsuse.sock
我来说说,这 1hr1min1s 和 三千五百万 有啥区别。 1hr1min1s 是累加、三千五百万是更复杂的折叠,因为汉字每个子意群都得带单位。 单位上升(“五百万”)的时候是乘,单位下降(“三千一百”)的时候是加,其实不必递归。 汉字没有 123 这种直接的数字(都是一百二十三)所以一个单位的显示还得递归地去做。 这个 show,不需要区分仅个位或大于十的情况,直接交给能输出数字的子程序即可。 NumUnit 已经做好了这一点,可它做不到最大单位也无法仅含个位情况下的递归输出。 而且如果 units…
找到了一个可以复用的点,但不知道是否值得为了它创建子类还是再次损失一点性能
1hr1min1s 也可以写成 1s1hr1min,可是大概有些人愿意做检测,仅允许 1hr1min1s 的情况。可以提供出一个 fun onUnitJoin(u1, u0) 来允许这种检查,可是 read/show 好像无法做到同时复用……
1hr1min1s 也可以写成 1s1hr1min,可是大概有些人愿意做检测,仅允许 1hr1min1s 的情况。可以提供出一个 fun onUnitJoin(u1, u0) 来允许这种检查,可是 read/show 好像无法做到同时复用……
/tmp/duangsuse.sock
我来说说,这 1hr1min1s 和 三千五百万 有啥区别。 1hr1min1s 是累加、三千五百万是更复杂的折叠,因为汉字每个子意群都得带单位。 单位上升(“五百万”)的时候是乘,单位下降(“三千一百”)的时候是加,其实不必递归。 汉字没有 123 这种直接的数字(都是一百二十三)所以一个单位的显示还得递归地去做。 这个 show,不需要区分仅个位或大于十的情况,直接交给能输出数字的子程序即可。 NumUnit 已经做好了这一点,可它做不到最大单位也无法仅含个位情况下的递归输出。 而且如果 units…
我说说绝句里的情况吧。除了负数和小数,刚才我提到的 pattern 都是支持的。
特殊处理大概就三种:
+ 零..九
+ 十一..十九
+ 一千零一
特殊处理大概就三种:
+ 零..九
+ 十一..十九
+ 一千零一
/tmp/duangsuse.sock
val hanDigit = MapPattern(mapOf( *"一二三四五六七八九".asIterable().zip(1..9).toArray()) ) val hanUnit = KeywordPattern<Int>().apply { mergeStrings("" to 1, "十" to 10, "百" to 100) mergeStrings("千" to 1000, "万" to 10000) } >>> val k=NumUnitTrie(hanDigit, hanUnit…
见识到本苏代码的复用性了吧?digitFor 和 MapPattern,一行代码自由切换读取变换算法,无痛迁移 😊
而且比函数式解析组合子更具有明确性,如果你用
正是因为写 Pattern 的时候不仅要 read,甚至要能够 show,而且还得支持 toPreetyDoc,所以敷衍、小聪明的写法就走不下去了,不是真正了解结构,写得了 from 写不出 to,整个完整的解析过程 ParserKt 都给管着,因为解析本身就和数据的表达方式转换脱不了干系。
而且比函数式解析组合子更具有明确性,如果你用
then 来完成 map value 的操作,怎么可能做到 show 的时候再 map back 呢~ 怎么会把 MapPattern 封装成一个类呢~正是因为写 Pattern 的时候不仅要 read,甚至要能够 show,而且还得支持 toPreetyDoc,所以敷衍、小聪明的写法就走不下去了,不是真正了解结构,写得了 from 写不出 to,整个完整的解析过程 ParserKt 都给管着,因为解析本身就和数据的表达方式转换脱不了干系。
/tmp/duangsuse.sock
val hanDigit = MapPattern(mapOf( *"一二三四五六七八九".asIterable().zip(1..9).toArray()) ) val hanUnit = KeywordPattern<Int>().apply { mergeStrings("" to 1, "十" to 10, "百" to 100) mergeStrings("千" to 1000, "万" to 10000) } >>> val k=NumUnitTrie(hanDigit, hanUnit…
我来说一个能解决输出问题,但是不能解决检查问题的:
val hanDigits = "一二三四五六七八九".asIterable().map(Char::toString).zip(1..9)
val hanDigit10s = hanDigits.map { it.run { "十"+first to 10+second } } // 闹着玩的,不能这么干
lateinit var hanShow: (Output<Char>, Int?) -> Unit
val hanDigit = object: KeywordPattern<Int>() {
init { mergeStrings(*hanDigits.toArray(), *hanDigit10s.toArray()) }
override fun show(s: Output<Char>, value: Int?) { if (value == null) return;
if (value in 1..9) super.show(s, value) else hanShow(s, value) }
}
val hanUnit = KeywordPattern<Int>().apply {
mergeStrings("" to 1, "十" to 10, "百" to 100)
mergeStrings("千" to 1000, "万" to 10000)
}
val k=NumUnitTrie(hanDigit, hanUnit, IntOps)
hanShow = k::show
/tmp/duangsuse.sock
我说说绝句里的情况吧。除了负数和小数,刚才我提到的 pattern 都是支持的。 特殊处理大概就三种: + 零..九 + 十一..十九 + 一千零一
我没支持到“亿”,因为那个数太大了
至于几百万的,在 NumUnitPattern 里,这很难实现,于是我避重就轻选择了特化支持 百万、千万这种单位,
但是
……算了,这情况也不好说
至于几百万的,在 NumUnitPattern 里,这很难实现,于是我避重就轻选择了特化支持 百万、千万这种单位,
但是
一千二百又百 (此时的“又”等价“零”)是支持的。……算了,这情况也不好说
/tmp/duangsuse.sock
我没支持到“亿”,因为那个数太大了 至于几百万的,在 NumUnitPattern 里,这很难实现,于是我避重就轻选择了特化支持 百万、千万这种单位, 但是一千二百又百 (此时的“又”等价“零”)是支持的。 ……算了,这情况也不好说
……“百万”的特例化支持,我也觉得是停止的好,因为它扰乱 show 的运作了
还是
还是
三百又万 吧,严谨不少。listOf("十", "百", "千").forEach { val k = this[it]!!*10000; this[it+"万"] = k; this[it+"万零"] = -k } 删了。k < 0 -> op.times(abs(k), i).also { s.error("零 form cannot be used in initial part") } 又删除了个
/tmp/duangsuse.sock
……“百万”的特例化支持,我也觉得是停止的好,因为它扰乱 show 的运作了 还是 三百又万 吧,严谨不少。 listOf("十", "百", "千").forEach { val k = this[it]!!*10000; this[it+"万"] = k; this[it+"万零"] = -k } 删了。 k < 0 -> op.times(abs(k), i).also { s.error("零 form cannot be used in initial part") } 又删除了个
算是勉强侥幸成功,最后又修了关于列号多记的一个小 bug,是我对 Feed 模型不够熟悉造成的。