├── .github └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── README.md ├── default.go ├── default_test.go ├── dict.go ├── go.mod ├── options.go ├── sat.go ├── sat_test.go └── word.txt /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: [push] 3 | jobs: 4 | build: 5 | name: Build 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Set up Go 9 | uses: actions/setup-go@v1 10 | with: 11 | go-version: 1.14 12 | id: go 13 | 14 | - name: Check out code into the Go module directory 15 | uses: actions/checkout@v1 16 | 17 | - name: Get dependencies 18 | run: | 19 | go get -v -t -d ./... 20 | 21 | - name: Test 22 | run: go test 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 高性能的简繁体转换 2 | 3 | ## 基本使用方式 4 | ```go 5 | dicter := DefaultDict() 6 | dicter.Read("什麼") 7 | dicter.ReadReverse("什么") 8 | ``` 9 | ## 支持自定义加载词库 10 | ```go 11 | DefaultDict(SetPath("/users/go/src/xxx.txt")) 12 | ``` 13 | 14 | ## 性能测试 15 | ```go 16 | goos: darwin 17 | goarch: amd64 18 | pkg: github.com/go-creed/sat 19 | BenchmarkNewDict 20 | BenchmarkNewDict-12 14721091 71.2 ns/op 21 | PASS 22 | ``` -------------------------------------------------------------------------------- /default.go: -------------------------------------------------------------------------------- 1 | package sat 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "log" 7 | "os" 8 | "path" 9 | "runtime" 10 | "sync" 11 | ) 12 | 13 | type defaultDict struct { 14 | mt sync.RWMutex 15 | data map[rune]rune 16 | dataReverse map[rune]rune 17 | opts Options 18 | } 19 | 20 | func (d *defaultDict) set(on, under rune) { 21 | d.mt.Lock() 22 | defer d.mt.Unlock() 23 | d.data[on] = under 24 | d.dataReverse[under] = on 25 | } 26 | 27 | func (d *defaultDict) getData(char rune) rune { 28 | d.mt.RLock() 29 | defer d.mt.RUnlock() 30 | if s, ok := d.data[char]; ok { 31 | return s 32 | } 33 | return char 34 | } 35 | 36 | func (d *defaultDict) getDataR(char rune) rune { 37 | d.mt.RLock() 38 | defer d.mt.RUnlock() 39 | if s, ok := d.dataReverse[char]; ok { 40 | return s 41 | } 42 | return char 43 | } 44 | 45 | func (d *defaultDict) defaultFile() (*os.File, error) { 46 | _, file, _, _ := runtime.Caller(1) 47 | base := path.Dir(file) + "/dict.txt" 48 | return os.Open(base) 49 | } 50 | 51 | func (d *defaultDict) Init(opts ...Option) error { 52 | for _, o := range opts { 53 | o(&d.opts) 54 | } 55 | return nil 56 | } 57 | 58 | func read(s string, f func(char rune) rune) string { 59 | r := []rune(s) 60 | for i := 0; i < len(r); i++ { 61 | r[i] = f(r[i]) //d.getData(r[i]) 62 | } 63 | return string(r) 64 | } 65 | 66 | func (d *defaultDict) Read(s string) string { 67 | return read(s, d.getData) 68 | } 69 | 70 | func (d *defaultDict) ReadReverse(s string) string { 71 | return read(s, d.getDataR) 72 | } 73 | 74 | var d *defaultDict 75 | 76 | func DefaultDict() Dicter { 77 | if d == nil { 78 | err := InitDefaultDict() 79 | if err != nil { 80 | log.Fatal(err) 81 | } 82 | } 83 | return d 84 | } 85 | func InitDefaultDict(opts ...Option) error { 86 | d = &defaultDict{ 87 | data: make(map[rune]rune), 88 | dataReverse: make(map[rune]rune), 89 | } 90 | d.Init(opts...) 91 | var ( 92 | err error 93 | file *os.File 94 | ) 95 | var simplified []rune 96 | var traditional []rune 97 | if d.opts.Path != "" { 98 | file, err = os.Open(d.opts.Path) 99 | if err != nil { 100 | return err 101 | } 102 | buf := bufio.NewScanner(file) 103 | var i int 104 | for buf.Scan() { 105 | text := buf.Text() 106 | switch i { 107 | case 0: 108 | simplified = []rune(text) 109 | case 1: 110 | traditional = []rune(text) 111 | } 112 | i++ 113 | } 114 | } else { 115 | simplified = defaultSimplified 116 | traditional = defaultTraditional 117 | } 118 | 119 | if len(simplified) != len(traditional) { 120 | return errors.New("the length of simplified varies from the length of traditional") 121 | } 122 | for i := 0; i < len(simplified) && i < len(traditional); i++ { 123 | d.set(traditional[i], simplified[i]) 124 | } 125 | return nil 126 | } 127 | -------------------------------------------------------------------------------- /default_test.go: -------------------------------------------------------------------------------- 1 | package sat 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestDefaultDict_Init(t *testing.T) { 8 | err := InitDefaultDict(SetPath("./word.txt")) 9 | if err != nil { 10 | t.Error(err) 11 | return 12 | } 13 | dicter := DefaultDict() 14 | t.Log(dicter.ReadReverse("一繁")) 15 | t.Log(dicter.Read("五")) 16 | } 17 | 18 | func BenchmarkDefaultDict_Read(b *testing.B) { 19 | dicter := DefaultDict() 20 | for i := 0; i < b.N; i++ { 21 | _ = dicter.Read("什麼") 22 | } 23 | } 24 | 25 | func BenchmarkDefaultDict_ReadReverse(b *testing.B) { 26 | dicter := DefaultDict() 27 | for i := 0; i < b.N; i++ { 28 | _ = dicter.ReadReverse("什么") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /dict.go: -------------------------------------------------------------------------------- 1 | package sat 2 | 3 | var defaultSimplified []rune = []rune("锕锿皑嗳蔼霭爱嫒碍暧瑷庵谙鹌鞍埯铵暗暗翱翱鳌鳌袄媪岙奥骜钯坝坝罢鲅霸摆呗败稗颁坂板钣办绊帮绑榜膀谤镑龅褒宝饱鸨褓报鲍杯杯鹎贝狈备背钡悖惫辈鞴奔奔贲锛绷绷逼秕笔币毕闭哔荜毙铋筚滗痹跸辟弊边笾编鳊贬变缏辩辫标飑骠膘镖飙飙飚镳表鳔鳖鳖别别瘪宾宾傧滨缤槟镔濒摈殡膑髌鬓鬓冰饼禀并并并拨剥钵钵饽驳驳钹铂博鹁钸卜补布钚财采采采彩睬踩参参参骖残蚕惭惭惨黪灿仓伧沧苍舱操艹册侧厕厕恻测策策层插馇锸查察镲诧钗侪虿觇掺搀婵谗禅馋缠蝉镡产产谄铲铲阐蒇冁忏颤伥阊鲳长肠苌尝尝偿厂厂场场怅畅钞车砗扯彻尘陈谌谌碜碜闯衬称龀趁榇谶柽蛏铛撑枨诚乘铖惩塍澄骋吃鸱痴驰迟齿耻饬炽敕冲冲虫宠铳俦帱绸畴筹酬酬酬踌雠雠丑瞅出刍厨锄锄雏橱蹰础储处处绌触传船钏囱疮窗窗窗床创怆捶棰锤锤春纯唇莼莼淳鹑醇绰辍龊词辞辞鹚鹚糍赐从匆匆苁枞葱骢聪丛丛凑辏粗粗蹴撺镩蹿窜篡脆村鹾锉错哒达沓鞑呆绐带玳贷单担郸殚瘅箪胆掸诞啖啖弹惮当当当裆挡挡党谠凼砀荡荡档导岛捣捣祷焘盗锝德灯邓凳镫堤镝籴敌涤觌诋抵抵递谛缔蒂颠巅癫点电垫钿淀雕雕雕鲷吊钓调铞谍喋叠叠叠蝶鲽钉顶订碇碇锭丢铥东冬岽岽鸫动冻峒栋胨兜斗斗斗钭豆窦读渎渎椟椟牍犊黩独笃赌睹妒镀端断缎煅锻簖队对兑怼镦吨墩趸炖钝顿遁夺铎朵垛缍堕跺讹讹峨锇鹅鹅额婀厄厄轭垩恶恶饿谔阏萼腭锷鹗颚鳄鳄儿鸸鲕尔迩饵铒贰发发罚罚阀法珐帆翻翻凡矾钒烦繁泛泛饭范贩钫鲂仿仿仿访纺飞绯鲱诽废费痱镄纷氛坟奋偾愤粪鲼丰风沣枫疯砜峰锋冯缝讽凤佛夫肤麸麸凫绂绋辐幞呒抚俯俯辅讣妇负附驸复复赋缚鲋赙鳆钆嘎该赅丐丐钙盖概干干杆尴尴秆赶绀赣冈刚岗纲肛钢杠戆皋槔糕缟稿镐诰锆纥胳鸽搁歌阁镉个个铬给亘耕赓绠鲠鲠宫躬龚巩贡沟钩钩缑构构诟购够觏轱鸪毂鹘诂谷钴蛊鹄鼓顾雇锢鲴刮鸹剐诖挂拐拐怪关关观鳏馆馆管管贯惯掼鹳罐广犷归妫妫龟规规闺瑰鲑轨匦诡刽刿柜贵鳜衮绲辊滚鲧鲧呙埚锅蝈国国帼掴果椁过铪骇顸函韩汉悍焊焊颔绗颃蚝嗥号皓皓颢灏诃合合和阂核盍颌阖贺鹤恒横轰哄红闳荭鸿黉讧糇鲎呼呼呼轷胡胡壶鹕糊浒户冱护沪鹱花花华哗哗骅铧划画话桦怀坏欢欢獾还环锾缳缓奂唤换涣焕痪鲩黄鳇恍谎诙咴挥晖珲辉辉徽回回回回蛔蛔蛔蛔汇汇汇会讳哕浍绘荟诲桧烩贿秽缋毁毁毁昏荤阍浑馄诨锪钬货获获祸镬讥击叽饥饥机玑矶鸡鸡迹迹积绩绩缉赍赍跻齑羁级极楫辑几虮挤计记纪际剂哜济继觊蓟霁鲚鲫骥夹夹浃家镓郏荚铗蛱颊贾钾价驾戋奸坚歼间艰监笺笺缄缣鲣鹣鞯拣枧俭茧捡笕减检睑裥锏简谫戬碱碱见饯剑剑荐贱涧舰渐谏溅践鉴鉴鉴键槛姜将浆僵缰缰讲奖桨蒋绛酱娇浇骄胶鲛鹪侥挢绞饺矫脚铰搅剿缴叫峤轿较阶阶疖秸节讦劫劫劫杰诘洁结颉鲒届诫斤仅卺紧谨锦馑尽尽劲进荩晋烬赆赆缙觐泾经茎荆惊鲸阱刭颈净弪径径胫痉竞靓静镜迥炯纠鸠阄揪韭旧厩厩救鹫驹锔局局举举榉龃讵钜剧惧据飓锯窭屦鹃镌镌卷锩倦桊狷绢隽眷决诀珏绝觉谲橛镢镢军钧皲俊浚骏咔开锎凯剀垲恺铠慨锴忾龛坎侃阚瞰糠糠闶炕钪考铐轲疴钶颏颗壳咳克克课骒缂锞肯垦恳坑铿抠眍叩扣寇库绔喾裤夸块侩郐哙狯脍宽髋款诓诳邝圹纩况旷矿矿贶亏岿窥窥匮愦愧溃蒉馈馈篑聩坤昆昆锟鲲捆捆阃困扩阔阔腊蜡辣来崃徕涞莱铼赉睐赖赖濑癞籁兰岚拦栏婪阑蓝谰澜褴斓篮镧览揽缆榄懒懒烂滥琅锒螂阆捞劳唠崂痨铹铑涝耢乐鳓缧镭诔垒泪类累棱厘梨狸离骊犁鹂漓缡蓠璃璃鲡篱藜礼里里逦锂鲤鳢历历历厉丽励呖坜沥苈枥疠隶隶俪栎疬疬荔轹郦栗砺砾莅莅粝蛎跞雳俩奁奁奁奁连帘怜涟莲联裢廉鲢镰敛敛琏脸裣蔹练娈炼炼恋殓链潋凉梁粮两魉谅辆辽疗缭镣鹩钌猎邻邻临淋辚磷磷鳞麟凛廪懔檩吝赁蔺躏灵灵岭凌铃棂棂绫菱龄鲮领溜刘浏留琉琉馏骝瘤镏柳柳绺锍鹨龙咙泷茏栊珑胧砻笼聋陇垄垄拢娄偻喽蒌楼耧蝼髅嵝搂篓瘘瘘镂噜撸卢庐芦垆垆泸炉炉栌胪轳鸬舻颅鲈卤卤虏掳鲁橹橹橹镥陆录赂辂渌禄滤戮辘鹭氇驴闾榈吕侣稆铝屡缕褛虑绿孪峦挛栾鸾脔滦銮乱略锊抡仑仑伦囵沦纶轮论罗罗猡脶萝逻椤锣箩骡骡镙裸裸泺络荦骆妈嬷麻蟆马犸玛码蚂杩骂骂唛吗买荬劢迈麦卖脉脉颟蛮馒瞒鳗满螨谩缦镘猫牦牦锚铆冒贸帽帽么没梅梅镅鹛霉镁门扪钔闷焖懑们蒙蒙蒙锰梦弥弥祢猕谜芈眯觅觅秘幂谧绵绵黾缅腼面面面鹋缈妙庙咩灭蔑珉缗缗闵泯闽悯愍鳘鸣铭谬缪谟馍馍模殁蓦镆谋亩钼幕拿拿镎内纳钠乃乃奶难楠楠馕挠铙蛲垴恼脑闹闹讷馁嫩铌霓鲵你拟昵腻鲇鲶捻辇撵念娘酿鸟茑袅袅袅捏陧聂啮啮嗫镊镍颞蹑孽宁咛拧狞柠聍泞纽钮农农侬哝浓脓弄驽钕疟暖暖傩诺锘讴欧殴瓯鸥呕怄沤盘盘蹒庞刨刨狍炮炮疱胚赔锫佩辔喷鹏碰碰纰铍毗罴骈谝骗骗缥飘飘贫嫔频颦评凭凭苹瓶鲆钋泼颇钷迫仆扑铺铺镤朴谱镨凄凄栖桤戚戚齐脐颀骐骑棋棋蛴旗蕲鳍岂启启绮气讫弃荠碛憩千扦迁佥钎牵悭铅谦愆签签骞荨钤钱钳乾乾潜浅肷谴缱堑椠呛羌戗枪跄锖锵镪强强墙墙嫱蔷樯樯抢羟襁襁炝硗硗跷锹锹缲乔侨荞桥谯憔憔鞒诮峭窍翘窃惬箧锲亲钦琴勤锓寝吣揿揿氢轻倾鲭苘顷请庆穷茕琼丘秋秋鳅鳅虬球赇巯区曲曲岖诎驱驱躯趋鸲癯龋阒觑觑觑权诠辁铨蜷颧绻劝却悫悫确阕阙鹊榷裙裙群冉让荛饶桡扰娆绕热认纫妊轫韧韧饪绒绒绒荣嵘蝾融冗铷颥缛软软蕊蕊蕊锐睿闰润箬洒飒萨腮鳃赛毵伞伞糁馓颡丧骚缫鳋扫涩涩啬铯穑杀纱铩鲨筛晒删姗钐膻闪陕讪骟缮膳赡鳝鳝伤殇觞垧赏绱烧绍赊蛇舍厍设慑慑摄滠绅诜审审谂婶渖肾渗升升声胜渑绳圣剩尸师虱诗狮湿湿酾鲺时识实蚀埘莳鲥驶势视视视试饰是柿贳适轼铈谥谥释寿寿兽绶书纾枢倏倏疏摅输赎薯术树竖竖庶数漱帅闩双谁税顺说说烁铄硕丝咝鸶缌蛳厮锶似祀饲驷俟松怂耸讼诵颂搜馊飕锼擞薮苏苏苏稣诉肃谡溯溯酸虽绥随岁岁谇孙狲荪飧损笋挲蓑缩唢琐锁它铊塔獭鳎挞闼骀台台台抬鲐态钛贪摊滩瘫坛坛坛坛坛昙谈锬谭袒钽叹叹赕汤铴镗饧糖傥烫趟涛绦绦绦掏韬鼗鼗讨铽腾誊藤锑绨啼缇鹈题蹄体体屉剃剃阗条龆鲦眺粜铫贴铁铁铁厅厅听听烃铤同铜统筒恸偷偷头秃图涂涂钍兔团团抟颓颓颓腿蜕饨臀托拖脱驮驼鸵鼍椭拓箨洼娲蛙袜袜腽弯湾纨玩顽挽绾碗碗万亡网往辋望为为韦围帏沩沩违闱涠维潍伟伪伪纬苇炜玮诿韪鲔卫卫谓喂喂猬温纹闻蚊蚊阌吻稳问瓮瓮挝涡莴窝蜗卧龌乌污污邬呜诬钨无吴芜坞坞妩妩庑忤怃鹉务误骛雾鹜诶牺晰溪锡嘻膝习席袭觋玺铣戏戏系系饩细郄阋舄虾侠峡狭硖辖辖吓厦仙纤纤籼莶跹锨鲜闲闲弦贤咸娴娴衔衔痫鹇鹇鹇显险猃蚬藓县岘苋现线线宪馅羡献乡乡芗厢缃骧镶详享响饷飨鲞向向项枭哓骁绡萧销潇箫嚣嚣晓筱效效啸啸蝎协邪胁胁挟谐携携撷缬鞋写泄泻绁绁绁亵谢蟹欣锌衅兴陉幸凶汹胸修鸺馐绣绣锈锈须须顼虚嘘许诩叙叙恤恤勖绪续婿溆轩谖喧萱萱萱萱悬旋璇选癣绚铉楦靴学泶鳕谑勋勋埙埙熏寻巡驯询浔鲟训讯徇逊丫压鸦鸦桠鸭哑痖亚讶垭娅氩咽恹恹烟胭阉腌讠闫严岩岩岩盐阎颜颜檐兖俨厣演魇鼹厌彦砚艳艳验验谚焰雁滟滟酽谳餍燕燕燕赝赝鸯扬扬扬阳杨炀疡养痒样夭尧肴轺窑窑谣摇遥瑶鳐药药鹞耀爷铘野野业叶页邺夜晔烨烨谒靥医医咿铱仪诒迤饴贻移遗颐彝彝钇舣蚁蚁义亿忆艺议异呓呓译峄怿绎诣驿轶谊缢瘗镒翳镱因阴阴荫荫殷铟喑堙吟淫淫银龈饮隐瘾应莺莺婴嘤撄缨罂罂樱璎鹦鹰茔荥荧莹萤营萦滢蓥潆蝇赢颍颖瘿映哟佣拥痈雍墉镛鳙咏涌恿恿踊优忧犹邮莜莸铀游鱿铕佑诱纡余欤鱼娱谀渔嵛逾觎舆与伛屿俣语龉驭吁吁妪饫郁狱钰预欲谕阈御鹆愈愈蓣誉鹬鸢鸳渊员园圆缘鼋猿猿辕橼远愿约岳钥钥钥悦钺阅阅跃粤云匀纭芸郧氲陨殒运郓恽晕酝酝愠韫韵蕴匝杂杂灾灾灾载簪咱咱攒攒攒趱暂赞赞赞錾瓒赃赃赃驵脏脏葬糟凿枣灶皂唣噪则择泽责啧帻箦赜贼谮缯锃赠揸齄扎扎札札轧闸闸铡诈栅榨斋债沾毡毡谵斩盏崭辗占战栈绽骣张獐涨帐胀账钊诏赵棹照哲辄蛰谪谪辙锗这浙鹧贞针针侦浈珍桢砧祯诊轸缜阵鸩赈镇争征峥挣狰钲睁铮筝证证诤郑帧症卮织栀执侄侄职絷跖踯只只址纸轵志制帙帙帜质栉挚致贽轾掷鸷滞骘稚稚置觯踬终钟钟钟肿种冢众众诌周轴帚纣咒绉昼荮皱骤朱诛诸猪铢槠潴橥烛属煮嘱瞩伫伫苎注贮驻筑铸箸专砖砖砖颛转啭赚撰馔妆妆庄桩装壮状骓锥坠缀缒赘谆准桌斫斫斫浊诼镯镯兹兹赀资缁谘辎锱龇鲻姊渍眦综棕踪鬃鬃总总偬纵粽邹驺诹鲰镞诅组躜缵纂钻钻罪樽鳟") 4 | 5 | var defaultTraditional []rune = []rune("錒鎄皚噯藹靄愛嬡礙曖璦菴諳鵪鞌垵銨闇晻翶翺鰲鼇襖媼嶴奧驁鈀垻壩罷鮁覇擺唄敗粺頒岅闆鈑辦絆幫綁牓艕謗鎊齙裦寶飽鴇緥報鮑盃桮鵯貝狽備揹鋇誖憊輩韝逩犇賁錛綳繃偪粃筆幣畢閉嗶蓽斃鉍篳潷痺蹕闢獘邊籩編鯿貶變緶辯辮標颮驃臕鏢飆飇飈鑣錶鰾鱉鼈別彆癟賓賔儐濱繽檳鑌瀕擯殯臏髕髩鬢氷餅稟並併竝撥剝缽鉢餑駁駮鈸鉑愽鵓鈽蔔補佈鈈財埰寀採綵倸跴參葠蓡驂殘蠶慚慙慘黲燦倉傖滄蒼艙撡艸冊側厠廁惻測筞筴層挿餷鍤査詧鑔詫釵儕蠆覘摻攙嬋讒禪饞纏蟬鐔產産諂剷鏟闡蕆囅懺顫倀閶鯧長腸萇嘗嚐償厰廠塲場悵暢鈔車硨撦徹塵陳訦諶硶磣闖襯稱齔趂櫬讖檉蟶鐺撐棖誠乗鋮懲堘澂騁喫鴟癡馳遲齒恥飭熾勅沖衝蟲寵銃儔幬綢疇籌詶酧醻躊讎讐醜矁齣芻廚耡鋤雛櫥躕礎儲処處絀觸傳舩釧囪瘡窓牎牕牀創愴搥箠錘鎚旾純脣蒓蓴湻鶉醕綽輟齪詞辤辭鶿鷀餈賜從怱悤蓯樅蔥驄聰樷叢湊輳觕麤蹵攛鑹躥竄簒脃邨鹺銼錯噠達遝韃獃紿帶蝳貸單擔鄲殫癉簞膽撣誕啗噉彈憚當儅噹襠擋攩黨讜氹碭蕩盪檔導島搗擣禱燾盜鍀悳燈鄧櫈鐙隄鏑糴敵滌覿詆牴觝遞諦締蔕顛巔癲點電墊鈿澱彫琱鵰鯛弔釣調銱諜啑曡疉疊蜨鰈釘頂訂矴椗錠丟銩東鼕崬崠鶇動凍峝棟腖兠鬥鬦鬭鈄荳竇讀凟瀆匵櫝牘犢黷獨篤賭覩妬鍍耑斷緞煆鍛籪隊對兌懟鐓噸墪躉燉鈍頓遯奪鐸朶垜綞墮跥訛譌峩鋨鵝鵞額娿戹阨軛堊惡噁餓諤閼蕚齶鍔鶚顎鰐鱷兒鴯鮞爾邇餌鉺貳發髮罰罸閥灋琺颿飜繙凣礬釩煩繁氾汎飯範販鈁魴徬倣髣訪紡飛緋鯡誹廢費疿鐨紛雰墳奮僨憤糞鱝豐風灃楓瘋碸峯鋒馮縫諷鳳彿伕膚麩粰鳧紱紼輻襆嘸撫俛頫輔訃婦負坿駙複復賦縛鮒賻鰒釓嘠該賅匃匄鈣蓋槩幹榦桿尲尷稈趕紺贛岡剛崗綱疘鋼槓戇臯橰餻縞槀鎬誥鋯紇肐鴿擱謌閣鎘個箇鉻給亙畊賡綆骾鯁宮躳龔鞏貢溝鈎鉤緱搆構詬購夠覯軲鴣轂鶻詁穀鈷蠱鵠皷顧僱錮鯝颳鴰剮詿掛枴柺恠関關觀鰥舘館琯筦貫慣摜鸛鑵廣獷歸媯嬀龜規槼閨瓌鮭軌匭詭劊劌櫃貴鱖袞緄輥滾鮌鯀咼堝鍋蟈囯國幗摑菓槨過鉿駭頇圅韓漢猂釬銲頷絎頏蠔獋號暠皜顥灝訶閤郃咊閡覈盇頜闔賀鶴恆橫轟鬨紅閎葒鴻黌訌餱鱟虖嘑謼軤衚鬍壺鶘餬滸戶沍護滬鸌芲蘤華嘩譁驊鏵劃畫話樺懷壞懽歡貛還環鍰繯緩奐喚換渙煥瘓鯇黃鰉怳謊詼噅揮暉琿煇輝幑囘囬廻迴蚘痐蛕蜖匯彙滙會諱噦澮繪薈誨檜燴賄穢繢燬譭毀昬葷閽渾餛諢鍃鈥貨獲穫禍鑊譏擊嘰飢饑機璣磯雞鷄跡蹟積勣績緝賫齎躋齏羈級極檝輯幾蟣擠計記紀際劑嚌濟繼覬薊霽鱭鯽驥夾裌浹傢鎵郟莢鋏蛺頰賈鉀價駕戔姦堅殲間艱監牋箋緘縑鰹鶼韉揀梘儉繭撿筧減檢瞼襇鐧簡譾戩鹼堿見餞劍劒薦賤澗艦漸諫濺踐鋻鑑鑒鍵檻薑將漿殭繮韁講獎槳蔣絳醬嬌澆驕膠鮫鷦僥撟絞餃矯腳鉸攪勦繳呌嶠轎較階堦癤稭節訐刦刧刼傑詰潔結頡鮚屆誡觔僅巹緊謹錦饉盡儘勁進藎晉燼賮贐縉覲涇經莖荊驚鯨穽剄頸淨弳徑逕脛痙競靚靜鏡逈埛糾鳩鬮揫韮舊廄廐捄鷲駒鋦侷跼舉擧櫸齟詎鉅劇懼據颶鋸窶屨鵑鎸鐫捲錈勌棬獧絹雋睠決訣玨絕覺譎橜鐝钁軍鈞皸儁濬駿哢開鐦凱剴塏愷鎧嘅鍇愾龕埳偘闞矙粇穅閌匟鈧攷銬軻痾鈳頦顆殼欬剋尅課騍緙錁肎墾懇阬鏗摳瞘敂釦宼庫絝嚳褲誇塊儈鄶噲獪膾寬髖欵誆誑鄺壙纊況曠礦鑛貺虧巋窺闚匱憒媿潰蕢餽饋簣聵堃崐崑錕鯤梱綑閫睏擴濶闊臘蠟辢來崍徠淶萊錸賚睞賴顂瀨癩籟蘭嵐攔欄惏闌藍讕瀾襤斕籃鑭覽攬纜欖嬾懶爛濫瑯鋃蜋閬撈勞嘮嶗癆鐒銠澇耮樂鰳縲鐳誄壘淚類纍稜釐棃貍離驪犂鸝灕縭蘺琍瓈鱺籬蔾禮裡裏邐鋰鯉鱧厤曆歷厲麗勵嚦壢瀝藶櫪癘隷隸儷櫟鬁癧茘轢酈慄礪礫涖蒞糲蠣躒靂倆匲奩匳籢連簾憐漣蓮聯褳亷鰱鐮斂歛璉臉襝蘞練孌煉鍊戀殮鏈瀲涼樑糧兩魎諒輛遼療繚鐐鷯釕獵鄰隣臨痳轔粦燐鱗麐凜廩懍檁恡賃藺躪霛靈嶺淩鈴櫺欞綾蔆齡鯪領霤劉瀏畱瑠璢餾騮癅鎦栁桺綹鋶鷚龍嚨瀧蘢櫳瓏朧礱籠聾隴壟壠攏婁僂嘍蔞樓耬螻髏嶁摟簍瘺瘻鏤嚕擼盧廬蘆壚罏瀘爐鑪櫨臚轤鸕艫顱鱸鹵滷虜擄魯櫓艣艪鑥陸錄賂輅淥祿濾剹轆鷺氌驢閭櫚呂侶穭鋁屢縷褸慮綠孿巒攣欒鸞臠灤鑾亂畧鋝掄侖崙倫圇淪綸輪論羅儸玀腡蘿邏欏鑼籮騾驘鏍躶臝濼絡犖駱媽嬤蔴蟇馬獁瑪碼螞榪罵駡嘜嗎買蕒勱邁麥賣脈衇顢蠻饅瞞鰻滿蟎謾縵鏝貓氂犛錨鉚冐貿夘戼麼沒楳槑鎇鶥黴鎂門捫鍆悶燜懣們懞濛矇錳夢彌瀰禰獼謎羋瞇覓覔祕冪謐綿緜黽緬靦靣麪麵鶓緲玅廟哶滅衊瑉緍緡閔冺閩憫湣鰵鳴銘謬繆謨饃饝糢歿驀鏌謀畝鉬幙拏挐鎿內納鈉廼迺嬭難枏柟饢撓鐃蟯堖惱腦閙鬧訥餒嫰鈮蜺鯢妳擬暱膩鮎鯰撚輦攆唸孃釀鳥蔦嫋裊嬝揑隉聶嚙齧囁鑷鎳顳躡孼寧嚀擰獰檸聹濘紐鈕農辳儂噥濃膿衖駑釹瘧煖煗儺諾鍩謳歐毆甌鷗嘔慪漚槃盤蹣龐鉋鑤麅砲礮皰肧賠錇珮轡噴鵬掽踫紕鈹毘羆駢諞騗騙縹飃飄貧嬪頻顰評凴憑蘋缾鮃釙潑頗鉕廹僕撲鋪舖鏷樸譜鐠悽淒棲榿慼鏚齊臍頎騏騎棊碁蠐旂蘄鰭豈啓啟綺氣訖棄薺磧憇韆扡遷僉釺牽慳鉛謙諐簽籤騫蕁鈐錢鉗亁乹潛淺膁譴繾塹槧嗆羗戧槍蹌錆鏘鏹彊強墻牆嬙薔檣艢搶羥繈繦熗墝磽蹺鍫鍬繰喬僑蕎橋譙癄顦鞽誚陗竅翹竊愜篋鍥親欽琹懃鋟寢唚搇撳氫輕傾鯖檾頃請慶窮煢瓊坵秌鞦鰌鰍虯毬賕巰區粬麯嶇詘敺驅軀趨鴝臒齲闃覰覷覻權詮輇銓踡顴綣勸卻愨慤確闋闕鵲搉帬裠羣冄讓蕘饒橈擾嬈繞熱認紉姙軔靭韌飪毧絨羢榮嶸蠑螎宂銣顬縟軟輭蕋橤蘂銳叡閏潤篛灑颯薩顋鰓賽毿傘繖糝饊顙喪騷繅鰠掃澁澀嗇銫穡殺紗鎩鯊篩曬刪姍釤羶閃陝訕騸繕饍贍鱓鱔傷殤觴坰賞緔燒紹賒虵捨厙設慴懾攝灄紳詵審讅諗嬸瀋腎滲昇陞聲勝澠繩聖賸屍師蝨詩獅溼濕釃鯴時識實蝕塒蒔鰣駛勢眎眡視試飾昰柹貰適軾鈰諡謚釋壽夀獸綬書紓樞倐儵疎攄輸贖藷術樹竪豎庻數潄帥閂雙誰稅順說説爍鑠碩絲噝鷥緦螄廝鍶佀禩飼駟竢鬆慫聳訟誦頌蒐餿颼鎪擻藪甦蘇囌穌訴肅謖泝遡痠雖綏隨嵗歲誶孫猻蓀飱損筍挱簑縮嗩瑣鎖牠鉈墖獺鰨撻闥駘臺颱檯擡鮐態鈦貪攤灘癱墰壇罈壜罎曇談錟譚襢鉭嘆歎賧湯鐋鏜餳餹儻燙蹚濤絛縚縧搯韜鞀鞉討鋱騰謄籐銻綈嗁緹鵜題蹏躰體屜薙鬀闐條齠鰷覜糶銚貼鉄銕鐵厛廳聼聽烴鋌衕銅統筩慟偸媮頭禿圖凃塗釷兎團糰摶頹頽穨骽蛻飩臋託拕脫馱駝鴕鼉橢搨籜窪媧鼃襪韤膃彎灣紈翫頑輓綰盌椀萬亾網徃輞朢為爲韋圍幃溈潙違闈潿維濰偉偽僞緯葦煒瑋諉韙鮪衛衞謂餧餵蝟溫紋聞螡蟁閿脗穩問甕罋撾渦萵窩蝸臥齷烏汙汚鄔嗚誣鎢無吳蕪塢隖娬嫵廡啎憮鵡務誤騖霧鶩誒犧晳谿錫譆厀習蓆襲覡璽銑戯戲繫係餼細郤鬩潟蝦俠峽狹硤轄鎋嚇廈僊縴纖秈薟躚鍁鮮閒閑絃賢鹹嫺嫻啣銜癇鷳鷴鷼顯險獫蜆蘚縣峴莧現綫線憲餡羨獻鄉鄕薌廂緗驤鑲詳亯響餉饗鯗嚮曏項梟嘵驍綃蕭銷瀟簫嚻囂曉篠効傚嘯歗蠍協衺脅脇挾諧擕攜擷纈鞵寫洩瀉紲絏緤褻謝蠏訢鋅釁興陘倖兇洶胷脩鵂饈綉繡銹鏽須鬚頊虛噓許詡敍敘卹賉勗緒續壻漵軒諼諠萲蕿藼蘐懸鏇璿選癬絢鉉楥鞾學澩鱈謔勛勳塤壎燻尋廵馴詢潯鱘訓訊狥遜枒壓鴉鵶椏鴨啞瘂亞訝埡婭氬嚥懨懕煙臙閹醃訁閆嚴喦巖巗鹽閻顏顔簷兗儼厴縯魘鼴厭彥硯艷豔騐驗諺燄鴈灧灩釅讞饜讌醼鷰贋贗鴦揚敭颺陽楊煬瘍養癢樣殀堯餚軺窯窰謠搖遙瑤鰩葯藥鷂燿爺鋣埜壄業葉頁鄴亱曄燁爗謁靨毉醫吚銥儀詒迆飴貽迻遺頤彜彞釔艤螘蟻義億憶藝議異囈讛譯嶧懌繹詣驛軼誼縊瘞鎰瞖鐿囙陰隂蔭廕慇銦瘖陻唫婬滛銀齦飲隱癮應鶯鸎嬰嚶攖纓甖罌櫻瓔鸚鷹塋滎熒瑩螢營縈瀅鎣瀠蠅贏潁穎癭暎喲傭擁癰雝鄘鏞鱅詠湧惥慂踴優憂猶郵蓧蕕鈾遊魷銪祐誘紆餘歟魚娛諛漁崳踰覦輿與傴嶼俁語齬馭訏籲嫗飫鬱獄鈺預慾諭閾禦鵒瘉癒蕷譽鷸鳶鴛淵員園圓緣黿猨蝯轅櫞遠願約嶽鑰鈅籥悅鉞閱閲躍粵雲勻紜蕓鄖氳隕殞運鄆惲暈醖醞慍韞韻蘊帀襍雜災烖菑載簮偺喒欑儹攢趲暫賛贊讚鏨瓚賍贓贜駔髒臟塟蹧鑿棗竈皁唕譟則擇澤責嘖幘簀賾賊譖繒鋥贈摣齇紥紮剳劄軋牐閘鍘詐柵搾齋債霑氈氊譫斬盞嶄輾佔戰棧綻驏張麞漲帳脹賬釗詔趙櫂炤喆輒蟄謫讁轍鍺這淛鷓貞針鍼偵湞珎楨碪禎診軫縝陣鴆賑鎮爭徴崢掙猙鉦睜錚箏証證諍鄭幀癥巵織梔執妷姪職縶蹠躑衹隻阯紙軹誌製祑袠幟質櫛摯緻贄輊擲鷙滯騭稺穉寘觶躓終鈡鍾鐘腫種塚眾衆謅週軸箒紂呪縐晝葤皺驟硃誅諸豬銖櫧瀦櫫燭屬煑囑矚佇竚苧註貯駐築鑄筯專塼甎磚顓轉囀賺譔饌妝粧莊樁裝壯狀騅錐墜綴縋贅諄準槕斮斲斵濁諑鋜鐲茲玆貲資緇諮輜錙齜鯔姉漬眥綜椶蹤騣鬉縂總傯縱糉鄒騶諏鯫鏃詛組躦纘篹鉆鑽辠罇鱒") 6 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-creed/sat 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /options.go: -------------------------------------------------------------------------------- 1 | package sat 2 | 3 | type Option func(*Options) 4 | 5 | type Options struct { 6 | Path string `json:"path"` 7 | } 8 | 9 | func SetPath(path string) Option { 10 | return func(args *Options) { 11 | args.Path = path 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sat.go: -------------------------------------------------------------------------------- 1 | package sat 2 | 3 | type Dicter interface { 4 | Init(opts ...Option) error 5 | Read(string) string 6 | ReadReverse(string) string 7 | } 8 | -------------------------------------------------------------------------------- /sat_test.go: -------------------------------------------------------------------------------- 1 | package sat 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var ( 8 | dicter = DefaultDict() 9 | ) 10 | 11 | func TestConvertPlain(t *testing.T) { 12 | cases := map[string]string{ 13 | "繁体中文": "繁體中文", 14 | "还带来了音乐等方面的重大更新": "還帶來了音樂等方麵的重大更新", 15 | "如果你是 iOS 14.5.1 用户,或者 Apple Music 的忠实粉丝,那么根本找不到理由去拒绝 iOS 14.6。": "如菓妳昰 iOS 14.5.1 用戶,或者 Apple Music 的忠實粉絲,那麼根本找不到理由去拒絕 iOS 14.6。", 16 | } 17 | 18 | for sc, expected := range cases { 19 | actually := dicter.ReadReverse(sc) 20 | if expected != actually { 21 | t.Errorf("\nexpected: %s\nactually: %s", expected, actually) 22 | } 23 | } 24 | 25 | } 26 | 27 | func TestConvertHTML(t *testing.T) { 28 | source := `

如果你最近看到有人打王者荣耀时情绪波动较大,不一定是因为 ta 的队友太坑或对手太强,而或许只因 ta 升级了 iOS 14.5.1。

29 |

无效的图片

30 |

发热、掉帧、卡顿,iOS 14.5.1 的性能 bug,成为近期 iPhone 用户吐槽最多的话题。无论你是哪款 iPhone,升级 iOS 14.5.1 之后,都有可能遇到性能缩水的问题。

` 31 | 32 | expect := `

如菓妳最近看到有人打王者榮燿時情緒波動較大,不一定昰囙爲 ta 的隊友太阬或對手太強,而或許隻囙 ta 陞級了 iOS 14.5.1。

33 |

無傚的圖片

34 |

髮熱、掉幀、卡頓,iOS 14.5.1 的性能 bug,成爲近期 iPhone 用戶吐槽最多的話題。無論妳昰哪欵 iPhone,陞級 iOS 14.5.1 之后,都有可能遇到性能縮水的問題。

` 35 | 36 | out := dicter.ReadReverse(source) 37 | if expect != out { 38 | t.Error(out) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /word.txt: -------------------------------------------------------------------------------- 1 | 一二三四繁 2 | 五六七八繁 --------------------------------------------------------------------------------